Compare commits
97 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e93a9a9ef | ||
|
|
23c1f7c72f | ||
|
|
12fba361bd | ||
|
|
6bcde572dd | ||
|
|
20a17607ae | ||
|
|
473caaff5b | ||
|
|
787552f832 | ||
|
|
5f945e2fcd | ||
|
|
c08da2d6ad | ||
|
|
4458920799 | ||
|
|
61fed8a3a6 | ||
|
|
efb3165e3d | ||
|
|
a493ba76b4 | ||
|
|
ae60a5657e | ||
|
|
feb60de5c3 | ||
|
|
c67644f1da | ||
|
|
9343b81afd | ||
|
|
71f53b4218 | ||
|
|
f131b0faeb | ||
|
|
6c64d5aff2 | ||
|
|
de594995da | ||
|
|
4c16a1a26f | ||
|
|
862e66202c | ||
|
|
2136a46ab7 | ||
|
|
b9c7e5c2c8 | ||
|
|
d86e88a622 | ||
|
|
7eac28e410 | ||
|
|
ea4c92f734 | ||
|
|
c9cd938dfd | ||
|
|
4c5e3d5f7a | ||
|
|
e2be180136 | ||
|
|
c9437e5244 | ||
|
|
24548b1f5c | ||
|
|
be0ecae108 | ||
|
|
fcd54c6479 | ||
|
|
08296f151e | ||
|
|
a134e924ff | ||
|
|
31ed6bae11 | ||
|
|
9a5ef835cc | ||
|
|
df0d3698ae | ||
|
|
51fc608f68 | ||
|
|
b30e19ba24 | ||
|
|
ec6b67d862 | ||
|
|
4d0b7f8496 | ||
|
|
e3b510a4b4 | ||
|
|
247d66a680 | ||
|
|
0047d8a01e | ||
|
|
efc0187537 | ||
|
|
b6fe8a0b3f | ||
|
|
ecaa038b4d | ||
|
|
4aac971864 | ||
|
|
6c93cdffb1 | ||
|
|
470714e2d1 | ||
|
|
6b888b0fa8 | ||
|
|
1a1393dad7 | ||
|
|
55412962c0 | ||
|
|
d920da2631 | ||
|
|
ff72bf2cb2 | ||
|
|
4efb9763d9 | ||
|
|
c600bc8652 | ||
|
|
f1806d237f | ||
|
|
9e331f9957 | ||
|
|
9169cbf728 | ||
|
|
1d03a0fa75 | ||
|
|
c9038af29e | ||
|
|
f3053920bf | ||
|
|
c7b31d24b9 | ||
|
|
8d0d0e1c7a | ||
|
|
4b8b223db2 | ||
|
|
728aca7703 | ||
|
|
a872030a35 | ||
|
|
79e7d7f4ba | ||
|
|
7f62a48ab5 | ||
|
|
b5415b6872 | ||
|
|
b76a1d987f | ||
|
|
ae2130470e | ||
|
|
ac6290bea7 | ||
|
|
4051bbbed7 | ||
|
|
2a7edda70a | ||
|
|
59b6ada7b7 | ||
|
|
9908434c14 | ||
|
|
668a10f9b9 | ||
|
|
fc4b45ebd3 | ||
|
|
1afe6d51ee | ||
|
|
1ae0f0f3f6 | ||
|
|
de0b35b974 | ||
|
|
ae88d01d8d | ||
|
|
d759de9f96 | ||
|
|
89d3e81be8 | ||
|
|
71f264c498 | ||
|
|
26417da5d3 | ||
|
|
b3b458edf9 | ||
|
|
74961d4dfb | ||
|
|
9ffa1801c7 | ||
|
|
4d4fe69223 | ||
|
|
0a75519ab5 | ||
|
|
3062a35eb1 |
@@ -373,8 +373,10 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
||||
val pictureInPictureParamsBuilder = PictureInPictureParams.Builder()
|
||||
.getPictureInPictureActionsBuilder().getPictureInPictureAspectBuilder()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
val isEmulationActive = emulationViewModel.emulationStarted.value &&
|
||||
!emulationViewModel.isEmulationStopping.value
|
||||
pictureInPictureParamsBuilder.setAutoEnterEnabled(
|
||||
BooleanSetting.PICTURE_IN_PICTURE.boolean
|
||||
BooleanSetting.PICTURE_IN_PICTURE.boolean && isEmulationActive
|
||||
)
|
||||
}
|
||||
setPictureInPictureParams(pictureInPictureParamsBuilder.build())
|
||||
|
||||
@@ -22,12 +22,16 @@ import androidx.core.graphics.drawable.toBitmap
|
||||
import androidx.core.graphics.drawable.toDrawable
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.AsyncDifferConfig
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.yuzu.yuzu_emu.HomeNavigationDirections
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.YuzuApplication
|
||||
@@ -92,28 +96,34 @@ class GameAdapter(private val activity: AppCompatActivity) :
|
||||
data = Uri.parse(holder.game.path)
|
||||
}
|
||||
|
||||
val layerDrawable = ResourcesCompat.getDrawable(
|
||||
YuzuApplication.appContext.resources,
|
||||
R.drawable.shortcut,
|
||||
null
|
||||
) as LayerDrawable
|
||||
layerDrawable.setDrawableByLayerId(
|
||||
R.id.shortcut_foreground,
|
||||
GameIconUtils.getGameIcon(holder.game).toDrawable(YuzuApplication.appContext.resources)
|
||||
)
|
||||
val inset = YuzuApplication.appContext.resources
|
||||
.getDimensionPixelSize(R.dimen.icon_inset)
|
||||
layerDrawable.setLayerInset(1, inset, inset, inset, inset)
|
||||
val shortcut = ShortcutInfoCompat.Builder(YuzuApplication.appContext, holder.game.path)
|
||||
.setShortLabel(holder.game.title)
|
||||
.setIcon(
|
||||
IconCompat.createWithAdaptiveBitmap(
|
||||
layerDrawable.toBitmap(config = Bitmap.Config.ARGB_8888)
|
||||
activity.lifecycleScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
val layerDrawable = ResourcesCompat.getDrawable(
|
||||
YuzuApplication.appContext.resources,
|
||||
R.drawable.shortcut,
|
||||
null
|
||||
) as LayerDrawable
|
||||
layerDrawable.setDrawableByLayerId(
|
||||
R.id.shortcut_foreground,
|
||||
GameIconUtils.getGameIcon(activity, holder.game)
|
||||
.toDrawable(YuzuApplication.appContext.resources)
|
||||
)
|
||||
)
|
||||
.setIntent(openIntent)
|
||||
.build()
|
||||
ShortcutManagerCompat.pushDynamicShortcut(YuzuApplication.appContext, shortcut)
|
||||
val inset = YuzuApplication.appContext.resources
|
||||
.getDimensionPixelSize(R.dimen.icon_inset)
|
||||
layerDrawable.setLayerInset(1, inset, inset, inset, inset)
|
||||
val shortcut =
|
||||
ShortcutInfoCompat.Builder(YuzuApplication.appContext, holder.game.path)
|
||||
.setShortLabel(holder.game.title)
|
||||
.setIcon(
|
||||
IconCompat.createWithAdaptiveBitmap(
|
||||
layerDrawable.toBitmap(config = Bitmap.Config.ARGB_8888)
|
||||
)
|
||||
)
|
||||
.setIntent(openIntent)
|
||||
.build()
|
||||
ShortcutManagerCompat.pushDynamicShortcut(YuzuApplication.appContext, shortcut)
|
||||
}
|
||||
}
|
||||
|
||||
val action = HomeNavigationDirections.actionGlobalEmulationActivity(holder.game)
|
||||
view.findNavController().navigate(action)
|
||||
|
||||
@@ -82,7 +82,6 @@ object Settings {
|
||||
|
||||
enum class MenuTag(val titleId: Int) {
|
||||
SECTION_ROOT(R.string.advanced_settings),
|
||||
SECTION_GENERAL(R.string.preferences_general),
|
||||
SECTION_SYSTEM(R.string.preferences_system),
|
||||
SECTION_RENDERER(R.string.preferences_graphics),
|
||||
SECTION_AUDIO(R.string.preferences_audio),
|
||||
|
||||
@@ -3,10 +3,13 @@
|
||||
|
||||
package org.yuzu.yuzu_emu.features.settings.model.view
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
|
||||
class RunnableSetting(
|
||||
titleId: Int,
|
||||
descriptionId: Int,
|
||||
val isRuntimeRunnable: Boolean,
|
||||
@DrawableRes val iconId: Int = 0,
|
||||
val runnable: () -> Unit
|
||||
) : SettingsItem(emptySetting, titleId, descriptionId) {
|
||||
override val type = TYPE_RUNNABLE
|
||||
|
||||
@@ -3,11 +3,14 @@
|
||||
|
||||
package org.yuzu.yuzu_emu.features.settings.model.view
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import org.yuzu.yuzu_emu.features.settings.model.Settings
|
||||
|
||||
class SubmenuSetting(
|
||||
titleId: Int,
|
||||
descriptionId: Int,
|
||||
@StringRes titleId: Int,
|
||||
@StringRes descriptionId: Int,
|
||||
@DrawableRes val iconId: Int,
|
||||
val menuKey: Settings.MenuTag
|
||||
) : SettingsItem(emptySetting, titleId, descriptionId) {
|
||||
override val type = TYPE_SUBMENU
|
||||
|
||||
@@ -20,7 +20,6 @@ import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.google.android.material.divider.MaterialDividerItemDecoration
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -68,15 +67,9 @@ class SettingsFragment : Fragment() {
|
||||
)
|
||||
|
||||
binding.toolbarSettingsLayout.title = getString(args.menuTag.titleId)
|
||||
val dividerDecoration = MaterialDividerItemDecoration(
|
||||
requireContext(),
|
||||
LinearLayoutManager.VERTICAL
|
||||
)
|
||||
dividerDecoration.isLastItemDecorated = false
|
||||
binding.listSettings.apply {
|
||||
adapter = settingsAdapter
|
||||
layoutManager = LinearLayoutManager(requireContext())
|
||||
addItemDecoration(dividerDecoration)
|
||||
}
|
||||
|
||||
binding.toolbarSettings.setNavigationOnClickListener {
|
||||
@@ -94,17 +87,6 @@ class SettingsFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
}
|
||||
launch {
|
||||
settingsViewModel.isUsingSearch.collectLatest {
|
||||
if (it) {
|
||||
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true)
|
||||
exitTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false)
|
||||
} else {
|
||||
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
|
||||
exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (args.menuTag == Settings.MenuTag.SECTION_ROOT) {
|
||||
@@ -112,8 +94,6 @@ class SettingsFragment : Fragment() {
|
||||
binding.toolbarSettings.setOnMenuItemClickListener {
|
||||
when (it.itemId) {
|
||||
R.id.action_search -> {
|
||||
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true)
|
||||
exitTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false)
|
||||
view.findNavController()
|
||||
.navigate(R.id.action_settingsFragment_to_settingsSearchFragment)
|
||||
true
|
||||
@@ -129,11 +109,6 @@ class SettingsFragment : Fragment() {
|
||||
setInsets()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
settingsViewModel.setIsUsingSearch(false)
|
||||
}
|
||||
|
||||
private fun setInsets() {
|
||||
ViewCompat.setOnApplyWindowInsetsListener(
|
||||
binding.root
|
||||
@@ -144,10 +119,9 @@ class SettingsFragment : Fragment() {
|
||||
val leftInsets = barInsets.left + cutoutInsets.left
|
||||
val rightInsets = barInsets.right + cutoutInsets.right
|
||||
|
||||
val sideMargin = resources.getDimensionPixelSize(R.dimen.spacing_medlarge)
|
||||
val mlpSettingsList = binding.listSettings.layoutParams as MarginLayoutParams
|
||||
mlpSettingsList.leftMargin = sideMargin + leftInsets
|
||||
mlpSettingsList.rightMargin = sideMargin + rightInsets
|
||||
mlpSettingsList.leftMargin = leftInsets
|
||||
mlpSettingsList.rightMargin = rightInsets
|
||||
binding.listSettings.layoutParams = mlpSettingsList
|
||||
binding.listSettings.updatePadding(
|
||||
bottom = barInsets.bottom
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
package org.yuzu.yuzu_emu.features.settings.ui
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Build
|
||||
import android.widget.Toast
|
||||
@@ -32,8 +31,6 @@ class SettingsFragmentPresenter(
|
||||
private val preferences: SharedPreferences
|
||||
get() = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
|
||||
|
||||
private val context: Context get() = YuzuApplication.appContext
|
||||
|
||||
// Extension for populating settings list based on paired settings
|
||||
fun ArrayList<SettingsItem>.add(key: String) {
|
||||
val item = SettingsItem.settingsItems[key]!!
|
||||
@@ -53,7 +50,6 @@ class SettingsFragmentPresenter(
|
||||
val sl = ArrayList<SettingsItem>()
|
||||
when (menuTag) {
|
||||
Settings.MenuTag.SECTION_ROOT -> addConfigSettings(sl)
|
||||
Settings.MenuTag.SECTION_GENERAL -> addGeneralSettings(sl)
|
||||
Settings.MenuTag.SECTION_SYSTEM -> addSystemSettings(sl)
|
||||
Settings.MenuTag.SECTION_RENDERER -> addGraphicsSettings(sl)
|
||||
Settings.MenuTag.SECTION_AUDIO -> addAudioSettings(sl)
|
||||
@@ -75,30 +71,53 @@ class SettingsFragmentPresenter(
|
||||
|
||||
private fun addConfigSettings(sl: ArrayList<SettingsItem>) {
|
||||
sl.apply {
|
||||
add(SubmenuSetting(R.string.preferences_general, 0, Settings.MenuTag.SECTION_GENERAL))
|
||||
add(SubmenuSetting(R.string.preferences_system, 0, Settings.MenuTag.SECTION_SYSTEM))
|
||||
add(SubmenuSetting(R.string.preferences_graphics, 0, Settings.MenuTag.SECTION_RENDERER))
|
||||
add(SubmenuSetting(R.string.preferences_audio, 0, Settings.MenuTag.SECTION_AUDIO))
|
||||
add(SubmenuSetting(R.string.preferences_debug, 0, Settings.MenuTag.SECTION_DEBUG))
|
||||
add(
|
||||
RunnableSetting(R.string.reset_to_default, 0, false) {
|
||||
settingsViewModel.setShouldShowResetSettingsDialog(true)
|
||||
}
|
||||
SubmenuSetting(
|
||||
R.string.preferences_system,
|
||||
R.string.preferences_system_description,
|
||||
R.drawable.ic_system_settings,
|
||||
Settings.MenuTag.SECTION_SYSTEM
|
||||
)
|
||||
)
|
||||
add(
|
||||
SubmenuSetting(
|
||||
R.string.preferences_graphics,
|
||||
R.string.preferences_graphics_description,
|
||||
R.drawable.ic_graphics,
|
||||
Settings.MenuTag.SECTION_RENDERER
|
||||
)
|
||||
)
|
||||
add(
|
||||
SubmenuSetting(
|
||||
R.string.preferences_audio,
|
||||
R.string.preferences_audio_description,
|
||||
R.drawable.ic_audio,
|
||||
Settings.MenuTag.SECTION_AUDIO
|
||||
)
|
||||
)
|
||||
add(
|
||||
SubmenuSetting(
|
||||
R.string.preferences_debug,
|
||||
R.string.preferences_debug_description,
|
||||
R.drawable.ic_code,
|
||||
Settings.MenuTag.SECTION_DEBUG
|
||||
)
|
||||
)
|
||||
add(
|
||||
RunnableSetting(
|
||||
R.string.reset_to_default,
|
||||
R.string.reset_to_default_description,
|
||||
false,
|
||||
R.drawable.ic_restore
|
||||
) { settingsViewModel.setShouldShowResetSettingsDialog(true) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addGeneralSettings(sl: ArrayList<SettingsItem>) {
|
||||
sl.apply {
|
||||
add(BooleanSetting.RENDERER_USE_SPEED_LIMIT.key)
|
||||
add(ShortSetting.RENDERER_SPEED_LIMIT.key)
|
||||
add(IntSetting.CPU_ACCURACY.key)
|
||||
add(BooleanSetting.PICTURE_IN_PICTURE.key)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addSystemSettings(sl: ArrayList<SettingsItem>) {
|
||||
sl.apply {
|
||||
add(BooleanSetting.RENDERER_USE_SPEED_LIMIT.key)
|
||||
add(ShortSetting.RENDERER_SPEED_LIMIT.key)
|
||||
add(BooleanSetting.USE_DOCKED_MODE.key)
|
||||
add(IntSetting.REGION_INDEX.key)
|
||||
add(IntSetting.LANGUAGE_INDEX.key)
|
||||
@@ -116,6 +135,7 @@ class SettingsFragmentPresenter(
|
||||
add(IntSetting.RENDERER_ANTI_ALIASING.key)
|
||||
add(IntSetting.RENDERER_SCREEN_LAYOUT.key)
|
||||
add(IntSetting.RENDERER_ASPECT_RATIO.key)
|
||||
add(BooleanSetting.PICTURE_IN_PICTURE.key)
|
||||
add(BooleanSetting.RENDERER_USE_DISK_SHADER_CACHE.key)
|
||||
add(BooleanSetting.RENDERER_FORCE_MAX_CLOCK.key)
|
||||
add(BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS.key)
|
||||
@@ -249,6 +269,7 @@ class SettingsFragmentPresenter(
|
||||
add(BooleanSetting.RENDERER_DEBUG.key)
|
||||
|
||||
add(HeaderSetting(R.string.cpu))
|
||||
add(IntSetting.CPU_ACCURACY.key)
|
||||
add(BooleanSetting.CPU_DEBUG_MODE.key)
|
||||
add(SettingsItem.FASTMEM_COMBINED)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
package org.yuzu.yuzu_emu.features.settings.ui.viewholder
|
||||
|
||||
import android.view.View
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import org.yuzu.yuzu_emu.NativeLibrary
|
||||
import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
|
||||
import org.yuzu.yuzu_emu.features.settings.model.view.RunnableSetting
|
||||
@@ -16,6 +17,19 @@ class RunnableViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA
|
||||
|
||||
override fun bind(item: SettingsItem) {
|
||||
setting = item as RunnableSetting
|
||||
if (item.iconId != 0) {
|
||||
binding.icon.visibility = View.VISIBLE
|
||||
binding.icon.setImageDrawable(
|
||||
ResourcesCompat.getDrawable(
|
||||
binding.icon.resources,
|
||||
item.iconId,
|
||||
binding.icon.context.theme
|
||||
)
|
||||
)
|
||||
} else {
|
||||
binding.icon.visibility = View.GONE
|
||||
}
|
||||
|
||||
binding.textSettingName.setText(item.nameId)
|
||||
if (item.descriptionId != 0) {
|
||||
binding.textSettingDescription.setText(item.descriptionId)
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
package org.yuzu.yuzu_emu.features.settings.ui.viewholder
|
||||
|
||||
import android.view.View
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
|
||||
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
|
||||
import org.yuzu.yuzu_emu.features.settings.model.view.SubmenuSetting
|
||||
@@ -15,6 +16,19 @@ class SubmenuViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAd
|
||||
|
||||
override fun bind(item: SettingsItem) {
|
||||
this.item = item as SubmenuSetting
|
||||
if (item.iconId != 0) {
|
||||
binding.icon.visibility = View.VISIBLE
|
||||
binding.icon.setImageDrawable(
|
||||
ResourcesCompat.getDrawable(
|
||||
binding.icon.resources,
|
||||
item.iconId,
|
||||
binding.icon.context.theme
|
||||
)
|
||||
)
|
||||
} else {
|
||||
binding.icon.visibility = View.GONE
|
||||
}
|
||||
|
||||
binding.textSettingName.setText(item.nameId)
|
||||
if (item.descriptionId != 0) {
|
||||
binding.textSettingDescription.setText(item.descriptionId)
|
||||
|
||||
@@ -114,10 +114,10 @@ class AboutFragment : Fragment() {
|
||||
val leftInsets = barInsets.left + cutoutInsets.left
|
||||
val rightInsets = barInsets.right + cutoutInsets.right
|
||||
|
||||
val mlpAppBar = binding.appbarAbout.layoutParams as MarginLayoutParams
|
||||
mlpAppBar.leftMargin = leftInsets
|
||||
mlpAppBar.rightMargin = rightInsets
|
||||
binding.appbarAbout.layoutParams = mlpAppBar
|
||||
val mlpToolbar = binding.toolbarAbout.layoutParams as MarginLayoutParams
|
||||
mlpToolbar.leftMargin = leftInsets
|
||||
mlpToolbar.rightMargin = rightInsets
|
||||
binding.toolbarAbout.layoutParams = mlpToolbar
|
||||
|
||||
val mlpScrollAbout = binding.scrollAbout.layoutParams as MarginLayoutParams
|
||||
mlpScrollAbout.leftMargin = leftInsets
|
||||
|
||||
@@ -40,8 +40,10 @@ class SettingsSearchFragment : Fragment() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false)
|
||||
returnTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true)
|
||||
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||
returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
|
||||
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
|
||||
exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
@@ -55,7 +57,6 @@ class SettingsSearchFragment : Fragment() {
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
settingsViewModel.setIsUsingSearch(true)
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
binding.searchText.setText(savedInstanceState.getString(SEARCH_TEXT))
|
||||
|
||||
@@ -18,8 +18,8 @@ class Game(
|
||||
val version: String = "",
|
||||
val isHomebrew: Boolean = false
|
||||
) : Parcelable {
|
||||
val keyAddedToLibraryTime get() = "${programId}_AddedToLibraryTime"
|
||||
val keyLastPlayedTime get() = "${programId}_LastPlayed"
|
||||
val keyAddedToLibraryTime get() = "${path}_AddedToLibraryTime"
|
||||
val keyLastPlayedTime get() = "${path}_LastPlayed"
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other !is Game) {
|
||||
|
||||
@@ -29,9 +29,6 @@ class SettingsViewModel : ViewModel() {
|
||||
val shouldReloadSettingsList: StateFlow<Boolean> get() = _shouldReloadSettingsList
|
||||
private val _shouldReloadSettingsList = MutableStateFlow(false)
|
||||
|
||||
val isUsingSearch: StateFlow<Boolean> get() = _isUsingSearch
|
||||
private val _isUsingSearch = MutableStateFlow(false)
|
||||
|
||||
val sliderProgress: StateFlow<Int> get() = _sliderProgress
|
||||
private val _sliderProgress = MutableStateFlow(-1)
|
||||
|
||||
@@ -57,10 +54,6 @@ class SettingsViewModel : ViewModel() {
|
||||
_shouldReloadSettingsList.value = value
|
||||
}
|
||||
|
||||
fun setIsUsingSearch(value: Boolean) {
|
||||
_isUsingSearch.value = value
|
||||
}
|
||||
|
||||
fun setSliderTextValue(value: Float, units: String) {
|
||||
_sliderProgress.value = value.toInt()
|
||||
_sliderTextValue.value = String.format(
|
||||
|
||||
@@ -8,9 +8,9 @@ import android.graphics.BitmapFactory
|
||||
import android.widget.ImageView
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import androidx.core.graphics.drawable.toDrawable
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import coil.ImageLoader
|
||||
import coil.decode.DataSource
|
||||
import coil.executeBlocking
|
||||
import coil.fetch.DrawableResult
|
||||
import coil.fetch.FetchResult
|
||||
import coil.fetch.Fetcher
|
||||
@@ -76,12 +76,13 @@ object GameIconUtils {
|
||||
imageLoader.enqueue(request)
|
||||
}
|
||||
|
||||
fun getGameIcon(game: Game): Bitmap {
|
||||
suspend fun getGameIcon(lifecycleOwner: LifecycleOwner, game: Game): Bitmap {
|
||||
val request = ImageRequest.Builder(YuzuApplication.appContext)
|
||||
.data(game)
|
||||
.lifecycle(lifecycleOwner)
|
||||
.error(R.drawable.default_icon)
|
||||
.build()
|
||||
return imageLoader.executeBlocking(request)
|
||||
return imageLoader.execute(request)
|
||||
.drawable!!.toBitmap(config = Bitmap.Config.ARGB_8888)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ struct Values {
|
||||
Settings::Linkage linkage;
|
||||
|
||||
// Android
|
||||
Settings::Setting<bool> picture_in_picture{linkage, true, "picture_in_picture",
|
||||
Settings::Setting<bool> picture_in_picture{linkage, false, "picture_in_picture",
|
||||
Settings::Category::Android};
|
||||
Settings::Setting<s32> screen_layout{linkage,
|
||||
5,
|
||||
|
||||
9
src/android/app/src/main/res/drawable/ic_audio.xml
Normal file
9
src/android/app/src/main/res/drawable/ic_audio.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24"
|
||||
android:viewportWidth="24">
|
||||
<path
|
||||
android:fillColor="?attr/colorControlNormal"
|
||||
android:pathData="M3,9v6h4l5,5L12,4L7,9L3,9zM16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v8.05c1.48,-0.73 2.5,-2.25 2.5,-4.02zM14,3.23v2.06c2.89,0.86 5,3.54 5,6.71s-2.11,5.85 -5,6.71v2.06c4.01,-0.91 7,-4.49 7,-8.77s-2.99,-7.86 -7,-8.77z" />
|
||||
</vector>
|
||||
9
src/android/app/src/main/res/drawable/ic_code.xml
Normal file
9
src/android/app/src/main/res/drawable/ic_code.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:fillColor="?attr/colorControlNormal"
|
||||
android:pathData="M320,720 L80,480l240,-240 57,57 -184,184 183,183 -56,56ZM640,720 L583,663 767,479 584,296 640,240 880,480 640,720Z"/>
|
||||
</vector>
|
||||
9
src/android/app/src/main/res/drawable/ic_graphics.xml
Normal file
9
src/android/app/src/main/res/drawable/ic_graphics.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:fillColor="?attr/colorControlNormal"
|
||||
android:pathData="M160,840q-33,0 -56.5,-23.5T80,760v-560q0,-33 23.5,-56.5T160,120h560q33,0 56.5,23.5T800,200v80h80v80h-80v80h80v80h-80v80h80v80h-80v80q0,33 -23.5,56.5T720,840L160,840ZM160,760h560v-560L160,200v560ZM240,680h200v-160L240,520v160ZM480,400h160v-120L480,280v120ZM240,480h200v-200L240,280v200ZM480,680h160v-240L480,440v240ZM160,200v560,-560Z"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:fillColor="?attr/colorControlNormal"
|
||||
android:pathData="M320,960q-17,0 -28.5,-11.5T280,920q0,-17 11.5,-28.5T320,880q17,0 28.5,11.5T360,920q0,17 -11.5,28.5T320,960ZM480,960q-17,0 -28.5,-11.5T440,920q0,-17 11.5,-28.5T480,880q17,0 28.5,11.5T520,920q0,17 -11.5,28.5T480,960ZM640,960q-17,0 -28.5,-11.5T600,920q0,-17 11.5,-28.5T640,880q17,0 28.5,11.5T680,920q0,17 -11.5,28.5T640,960ZM320,800q-33,0 -56.5,-23.5T240,720v-640q0,-33 23.5,-56.5T320,0h320q33,0 56.5,23.5T720,80v640q0,33 -23.5,56.5T640,800L320,800ZM320,720h320v-40L320,680v40ZM320,600h320v-400L320,200v400ZM320,120h320v-40L320,80v40ZM320,120v-40,40ZM320,720v-40,40Z"/>
|
||||
</vector>
|
||||
233
src/android/app/src/main/res/layout-w600dp/fragment_about.xml
Normal file
233
src/android/app/src/main/res/layout-w600dp/fragment_about.xml
Normal file
@@ -0,0 +1,233 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout 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"
|
||||
android:id="@+id/coordinator_about"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/colorSurface">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appbar_about"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar_about"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
app:navigationIcon="@drawable/ic_back"
|
||||
app:title="@string/about" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/scroll_about"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fadeScrollbars="false"
|
||||
android:scrollbars="vertical"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/content_about"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/image_logo"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="200dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:padding="20dp"
|
||||
android:src="@drawable/ic_yuzu_title" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingVertical="16dp">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
style="@style/TextAppearance.Material3.TitleMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="24dp"
|
||||
android:text="@string/about"
|
||||
android:textAlignment="viewStart" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="24dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:text="@string/about_app_description"
|
||||
android:textAlignment="viewStart" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.divider.MaterialDivider
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="20dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/button_contributors"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingVertical="16dp">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
style="@style/TextAppearance.Material3.TitleMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="24dp"
|
||||
android:text="@string/contributors"
|
||||
android:textAlignment="viewStart" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="24dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:text="@string/contributors_description"
|
||||
android:textAlignment="viewStart" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.divider.MaterialDivider
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="20dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/button_licenses"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingVertical="16dp">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
style="@style/TextAppearance.Material3.TitleMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="24dp"
|
||||
android:text="@string/licenses"
|
||||
android:textAlignment="viewStart" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="24dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:text="@string/licenses_description"
|
||||
android:textAlignment="viewStart" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.divider.MaterialDivider
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="20dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/button_build_hash"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingVertical="16dp">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
style="@style/TextAppearance.Material3.TitleMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="24dp"
|
||||
android:text="@string/build"
|
||||
android:textAlignment="viewStart" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/text_build_hash"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="24dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:textAlignment="viewStart"
|
||||
tools:text="abc123" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.divider.MaterialDivider
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="20dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="40dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_discord"
|
||||
style="?attr/materialIconButtonStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
app:icon="@drawable/ic_discord"
|
||||
app:iconGravity="textEnd"
|
||||
app:iconSize="24dp"
|
||||
app:iconTint="?attr/colorOnSurface" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_website"
|
||||
style="?attr/materialIconButtonStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
app:icon="@drawable/ic_website"
|
||||
app:iconGravity="textEnd"
|
||||
app:iconSize="24dp"
|
||||
app:iconTint="?attr/colorOnSurface" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_github"
|
||||
style="?attr/materialIconButtonStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
app:icon="@drawable/ic_github"
|
||||
app:iconGravity="textEnd"
|
||||
app:iconSize="24dp"
|
||||
app:iconTint="?attr/colorOnSurface" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
@@ -6,8 +6,8 @@
|
||||
android:id="@+id/option_card"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="12dp"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:layout_marginHorizontal="12dp"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:backgroundTint="?attr/colorSurfaceVariant"
|
||||
android:clickable="true"
|
||||
|
||||
@@ -38,17 +38,17 @@
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/image_logo"
|
||||
android:layout_width="250dp"
|
||||
android:layout_height="250dp"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_width="150dp"
|
||||
android:layout_height="150dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginBottom="28dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:src="@drawable/ic_yuzu_title" />
|
||||
|
||||
<com.google.android.material.divider.MaterialDivider
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="20dp"
|
||||
android:layout_marginTop="28dp" />
|
||||
android:layout_marginHorizontal="20dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -139,7 +139,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/show_fps_text"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
style="@style/TextAppearance.Material3.BodySmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="left"
|
||||
@@ -147,7 +147,8 @@
|
||||
android:focusable="false"
|
||||
android:paddingHorizontal="20dp"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="12sp"
|
||||
android:shadowColor="@android:color/black"
|
||||
android:shadowRadius="3"
|
||||
tools:ignore="RtlHardcoded" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
@@ -14,13 +14,14 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="?attr/colorSurface">
|
||||
android:background="?attr/colorSurface"
|
||||
android:paddingHorizontal="8dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/logo_image"
|
||||
android:layout_width="128dp"
|
||||
android:layout_height="128dp"
|
||||
android:layout_margin="64dp"
|
||||
android:layout_width="96dp"
|
||||
android:layout_height="96dp"
|
||||
android:layout_marginVertical="32dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:src="@drawable/ic_yuzu_full" />
|
||||
|
||||
|
||||
@@ -127,6 +127,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false"
|
||||
android:paddingVertical="4dp"
|
||||
app:checkedChip="@id/chip_recently_played"
|
||||
app:chipSpacingHorizontal="12dp"
|
||||
app:singleLine="true"
|
||||
app:singleSelection="true">
|
||||
|
||||
@@ -10,41 +10,59 @@
|
||||
android:focusable="true"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="72dp"
|
||||
android:padding="@dimen/spacing_large">
|
||||
android:padding="16dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/text_setting_name"
|
||||
style="@style/TextAppearance.Material3.HeadlineMedium"
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:visibility="gone"
|
||||
app:tint="?attr/colorOnSurface" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAlignment="viewStart"
|
||||
android:textSize="16sp"
|
||||
app:lineHeight="22dp"
|
||||
tools:text="Setting Name" />
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/text_setting_description"
|
||||
style="@style/TextAppearance.Material3.BodySmall"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/spacing_small"
|
||||
android:textAlignment="viewStart"
|
||||
tools:text="@string/app_disclaimer" />
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/text_setting_name"
|
||||
style="@style/TextAppearance.Material3.HeadlineMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAlignment="viewStart"
|
||||
android:textSize="17sp"
|
||||
app:lineHeight="22dp"
|
||||
tools:text="Setting Name" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/text_setting_value"
|
||||
style="@style/TextAppearance.Material3.LabelMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/spacing_small"
|
||||
android:textAlignment="viewStart"
|
||||
android:textStyle="bold"
|
||||
tools:text="1x" />
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/text_setting_description"
|
||||
style="@style/TextAppearance.Material3.BodySmall"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/spacing_small"
|
||||
android:textAlignment="viewStart"
|
||||
tools:text="@string/app_disclaimer" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/text_setting_value"
|
||||
style="@style/TextAppearance.Material3.LabelMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/spacing_small"
|
||||
android:textAlignment="viewStart"
|
||||
android:textStyle="bold"
|
||||
android:textSize="13sp"
|
||||
tools:text="1x" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@@ -8,9 +8,7 @@
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:minHeight="72dp"
|
||||
android:paddingVertical="@dimen/spacing_large"
|
||||
android:paddingStart="@dimen/spacing_large"
|
||||
android:paddingEnd="24dp">
|
||||
android:padding="16dp">
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/switch_widget"
|
||||
@@ -24,7 +22,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginEnd="@dimen/spacing_large"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_toStartOf="@+id/switch_widget"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical">
|
||||
@@ -35,7 +33,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAlignment="viewStart"
|
||||
android:textSize="16sp"
|
||||
android:textSize="17sp"
|
||||
app:lineHeight="28dp"
|
||||
tools:text="@string/frame_limit_enable" />
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start|center_vertical"
|
||||
android:paddingHorizontal="@dimen/spacing_large"
|
||||
android:paddingVertical="16dp"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="?attr/colorPrimary"
|
||||
android:textStyle="bold"
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
<resources>
|
||||
|
||||
<string-array name="regionNames">
|
||||
<item>@string/auto</item>
|
||||
<item>@string/region_australia</item>
|
||||
<item>@string/region_china</item>
|
||||
<item>@string/region_europe</item>
|
||||
@@ -13,7 +12,6 @@
|
||||
</string-array>
|
||||
|
||||
<integer-array name="regionValues">
|
||||
<item>-1</item>
|
||||
<item>3</item>
|
||||
<item>4</item>
|
||||
<item>2</item>
|
||||
|
||||
@@ -240,6 +240,7 @@
|
||||
<string name="shutting_down">Shutting down…</string>
|
||||
<string name="reset_setting_confirmation">Do you want to reset this setting back to its default value?</string>
|
||||
<string name="reset_to_default">Reset to default</string>
|
||||
<string name="reset_to_default_description">Resets all advanced settings</string>
|
||||
<string name="reset_all_settings">Reset all settings?</string>
|
||||
<string name="reset_all_settings_description">All advanced settings will be reset to their default configuration. This can not be undone.</string>
|
||||
<string name="settings_reset">Settings reset</string>
|
||||
@@ -271,10 +272,14 @@
|
||||
<string name="preferences_settings">Settings</string>
|
||||
<string name="preferences_general">General</string>
|
||||
<string name="preferences_system">System</string>
|
||||
<string name="preferences_system_description">Docked mode, region, language</string>
|
||||
<string name="preferences_graphics">Graphics</string>
|
||||
<string name="preferences_graphics_description">Accuracy level, resolution, shader cache</string>
|
||||
<string name="preferences_audio">Audio</string>
|
||||
<string name="preferences_audio_description">Output engine, volume</string>
|
||||
<string name="preferences_theme">Theme and color</string>
|
||||
<string name="preferences_debug">Debug</string>
|
||||
<string name="preferences_debug_description">CPU/GPU debugging, graphics API, fastmem</string>
|
||||
|
||||
<!-- ROM loading errors -->
|
||||
<string name="loader_error_encrypted">Your ROM is encrypted</string>
|
||||
|
||||
@@ -12,7 +12,7 @@ bool IsValidChannelCount(u32 channel_count) {
|
||||
}
|
||||
|
||||
bool IsValidStreamCounts(u32 total_stream_count, u32 stereo_stream_count) {
|
||||
return total_stream_count > 0 && stereo_stream_count > 0 &&
|
||||
return total_stream_count > 0 && static_cast<s32>(stereo_stream_count) >= 0 &&
|
||||
stereo_stream_count <= total_stream_count && IsValidChannelCount(total_stream_count);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@@ -148,7 +148,7 @@ Result OpusDecoder::DecodeInterleavedForMultiStream(u32* out_data_size, u64* out
|
||||
auto* header_p{reinterpret_cast<const OpusPacketHeader*>(input_data.data())};
|
||||
OpusPacketHeader header{ReverseHeader(*header_p)};
|
||||
|
||||
LOG_ERROR(Service_Audio, "header size 0x{:X} input data size 0x{:X} in_data size 0x{:X}",
|
||||
LOG_TRACE(Service_Audio, "header size 0x{:X} input data size 0x{:X} in_data size 0x{:X}",
|
||||
header.size, input_data.size_bytes(), in_data.size_bytes());
|
||||
|
||||
R_UNLESS(in_data.size_bytes() >= header.size &&
|
||||
|
||||
@@ -146,7 +146,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
paused = true;
|
||||
SignalPause();
|
||||
if (cubeb_stream_stop(stream_backend) != CUBEB_OK) {
|
||||
LOG_CRITICAL(Audio_Sink, "Error stopping cubeb stream");
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ public:
|
||||
if (device == 0 || paused) {
|
||||
return;
|
||||
}
|
||||
paused = true;
|
||||
SignalPause();
|
||||
SDL_PauseAudioDevice(device, 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -282,11 +282,19 @@ u64 SinkStream::GetExpectedPlayedSampleCount() {
|
||||
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; });
|
||||
[this]() { return paused || queued_buffers < max_queue_size; });
|
||||
if (queued_buffers > max_queue_size + 3) {
|
||||
Common::CondvarWait(release_cv, lk, stop_token,
|
||||
[this] { return queued_buffers < max_queue_size; });
|
||||
[this] { return paused || queued_buffers < max_queue_size; });
|
||||
}
|
||||
}
|
||||
|
||||
void SinkStream::SignalPause() {
|
||||
{
|
||||
std::scoped_lock lk{release_mutex};
|
||||
paused = true;
|
||||
}
|
||||
release_cv.notify_one();
|
||||
}
|
||||
|
||||
} // namespace AudioCore::Sink
|
||||
|
||||
@@ -213,6 +213,12 @@ public:
|
||||
*/
|
||||
void WaitFreeSpace(std::stop_token stop_token);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Unblocks the ADSP if the stream is paused.
|
||||
*/
|
||||
void SignalPause();
|
||||
|
||||
protected:
|
||||
/// Core system
|
||||
Core::System& system;
|
||||
|
||||
@@ -203,6 +203,8 @@ const char* TranslateCategory(Category category) {
|
||||
case Category::Ui:
|
||||
case Category::UiGeneral:
|
||||
return "UI";
|
||||
case Category::UiAudio:
|
||||
return "UiAudio";
|
||||
case Category::UiLayout:
|
||||
return "UiLayout";
|
||||
case Category::UiGameList:
|
||||
|
||||
@@ -153,7 +153,7 @@ struct Values {
|
||||
true,
|
||||
true};
|
||||
Setting<bool, false> audio_muted{
|
||||
linkage, false, "audio_muted", Category::Audio, Specialization::Default, false, true};
|
||||
linkage, false, "audio_muted", Category::Audio, Specialization::Default, true, true};
|
||||
Setting<bool, false> dump_audio_commands{
|
||||
linkage, false, "dump_audio_commands", Category::Audio, Specialization::Default, false};
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ enum class Category : u32 {
|
||||
AddOns,
|
||||
Controls,
|
||||
Ui,
|
||||
UiAudio,
|
||||
UiGeneral,
|
||||
UiLayout,
|
||||
UiGameList,
|
||||
|
||||
@@ -521,11 +521,21 @@ add_library(core STATIC
|
||||
hle/service/grc/grc.h
|
||||
hle/service/hid/hid.cpp
|
||||
hle/service/hid/hid.h
|
||||
hle/service/hid/hid_debug_server.cpp
|
||||
hle/service/hid/hid_debug_server.h
|
||||
hle/service/hid/hid_firmware_settings.cpp
|
||||
hle/service/hid/hid_firmware_settings.h
|
||||
hle/service/hid/hid_server.cpp
|
||||
hle/service/hid/hid_server.h
|
||||
hle/service/hid/hid_system_server.cpp
|
||||
hle/service/hid/hid_system_server.h
|
||||
hle/service/hid/hidbus.cpp
|
||||
hle/service/hid/hidbus.h
|
||||
hle/service/hid/irs.cpp
|
||||
hle/service/hid/irs.h
|
||||
hle/service/hid/irs_ring_lifo.h
|
||||
hle/service/hid/resource_manager.cpp
|
||||
hle/service/hid/resource_manager.h
|
||||
hle/service/hid/ring_lifo.h
|
||||
hle/service/hid/xcd.cpp
|
||||
hle/service/hid/xcd.h
|
||||
@@ -715,6 +725,7 @@ add_library(core STATIC
|
||||
hle/service/nvnflinger/producer_listener.h
|
||||
hle/service/nvnflinger/status.h
|
||||
hle/service/nvnflinger/ui/fence.h
|
||||
hle/service/nvnflinger/ui/graphic_buffer.cpp
|
||||
hle/service/nvnflinger/ui/graphic_buffer.h
|
||||
hle/service/nvnflinger/window.h
|
||||
hle/service/olsc/olsc.cpp
|
||||
|
||||
@@ -153,6 +153,14 @@ void ARM_Interface::Run() {
|
||||
Kernel::KThread* current_thread{Kernel::GetCurrentThreadPointer(system.Kernel())};
|
||||
HaltReason hr{};
|
||||
|
||||
// If the thread is scheduled for termination, exit the thread.
|
||||
if (current_thread->HasDpc()) {
|
||||
if (current_thread->IsTerminationRequested()) {
|
||||
current_thread->Exit();
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
// Notify the debugger and go to sleep if a step was performed
|
||||
// and this thread has been scheduled again.
|
||||
if (current_thread->GetStepState() == StepState::StepPerformed) {
|
||||
@@ -174,14 +182,6 @@ void ARM_Interface::Run() {
|
||||
}
|
||||
system.ExitCPUProfile();
|
||||
|
||||
// If the thread is scheduled for termination, exit the thread.
|
||||
if (current_thread->HasDpc()) {
|
||||
if (current_thread->IsTerminationRequested()) {
|
||||
current_thread->Exit();
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
// Notify the debugger and go to sleep if a breakpoint was hit,
|
||||
// or if the thread is unable to continue for any reason.
|
||||
if (True(hr & HaltReason::InstructionBreakpoint) || True(hr & HaltReason::PrefetchAbort)) {
|
||||
|
||||
@@ -76,6 +76,7 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) {
|
||||
}
|
||||
|
||||
void CoreTiming::ClearPendingEvents() {
|
||||
std::scoped_lock lock{basic_lock};
|
||||
event_queue.clear();
|
||||
}
|
||||
|
||||
@@ -113,6 +114,7 @@ bool CoreTiming::IsRunning() const {
|
||||
}
|
||||
|
||||
bool CoreTiming::HasPendingEvents() const {
|
||||
std::scoped_lock lock{basic_lock};
|
||||
return !(wait_set && event_queue.empty());
|
||||
}
|
||||
|
||||
|
||||
@@ -161,7 +161,7 @@ private:
|
||||
std::shared_ptr<EventType> ev_lost;
|
||||
Common::Event event{};
|
||||
Common::Event pause_event{};
|
||||
std::mutex basic_lock;
|
||||
mutable std::mutex basic_lock;
|
||||
std::mutex advance_lock;
|
||||
std::unique_ptr<std::jthread> timer_thread;
|
||||
std::atomic<bool> paused{};
|
||||
|
||||
@@ -38,14 +38,6 @@ using TouchParams = std::array<Common::ParamPackage, MaxTouchDevices>;
|
||||
using ConsoleMotionValues = ConsoleMotionInfo;
|
||||
using TouchValues = std::array<Common::Input::TouchStatus, MaxTouchDevices>;
|
||||
|
||||
struct TouchFinger {
|
||||
u64 last_touch{};
|
||||
Common::Point<float> position{};
|
||||
u32 id{};
|
||||
TouchAttribute attribute{};
|
||||
bool pressed{};
|
||||
};
|
||||
|
||||
// Contains all motion related data that is used on the services
|
||||
struct ConsoleMotion {
|
||||
Common::Vec3f accel{};
|
||||
|
||||
@@ -356,6 +356,14 @@ struct TouchState {
|
||||
};
|
||||
static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size");
|
||||
|
||||
struct TouchFinger {
|
||||
u64 last_touch{};
|
||||
Common::Point<float> position{};
|
||||
u32 id{};
|
||||
TouchAttribute attribute{};
|
||||
bool pressed{};
|
||||
};
|
||||
|
||||
// This is nn::hid::TouchScreenConfigurationForNx
|
||||
struct TouchScreenConfigurationForNx {
|
||||
TouchScreenModeForNx mode{TouchScreenModeForNx::UseSystemSetting};
|
||||
|
||||
@@ -5,13 +5,14 @@
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hid/input_interpreter.h"
|
||||
#include "core/hle/service/hid/controllers/npad.h"
|
||||
#include "core/hle/service/hid/hid.h"
|
||||
#include "core/hle/service/hid/hid_server.h"
|
||||
#include "core/hle/service/hid/resource_manager.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
|
||||
InputInterpreter::InputInterpreter(Core::System& system)
|
||||
: npad{system.ServiceManager()
|
||||
.GetService<Service::HID::Hid>("hid")
|
||||
->GetAppletResource()
|
||||
.GetService<Service::HID::IHidServer>("hid")
|
||||
->GetResourceManager()
|
||||
->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad)} {
|
||||
ResetButtonStates();
|
||||
}
|
||||
|
||||
@@ -1617,9 +1617,9 @@ void KPageTableBase::RemapPageGroup(PageLinkedList* page_list, KProcessAddress a
|
||||
const KMemoryInfo info = it->GetMemoryInfo();
|
||||
|
||||
// Determine the range to map.
|
||||
KProcessAddress map_address = std::max(info.GetAddress(), GetInteger(start_address));
|
||||
KProcessAddress map_address = std::max<u64>(info.GetAddress(), GetInteger(start_address));
|
||||
const KProcessAddress map_end_address =
|
||||
std::min(info.GetEndAddress(), GetInteger(end_address));
|
||||
std::min<u64>(info.GetEndAddress(), GetInteger(end_address));
|
||||
ASSERT(map_end_address != map_address);
|
||||
|
||||
// Determine if we should disable head merge.
|
||||
|
||||
@@ -8,12 +8,17 @@ namespace Service::HID {
|
||||
ControllerBase::ControllerBase(Core::HID::HIDCore& hid_core_) : hid_core(hid_core_) {}
|
||||
ControllerBase::~ControllerBase() = default;
|
||||
|
||||
void ControllerBase::ActivateController() {
|
||||
Result ControllerBase::Activate() {
|
||||
if (is_activated) {
|
||||
return;
|
||||
return ResultSuccess;
|
||||
}
|
||||
is_activated = true;
|
||||
OnInit();
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result ControllerBase::Activate(u64 aruid) {
|
||||
return Activate();
|
||||
}
|
||||
|
||||
void ControllerBase::DeactivateController() {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Core::Timing {
|
||||
class CoreTiming;
|
||||
@@ -31,7 +32,8 @@ public:
|
||||
// When the controller is requesting a motion update for the shared memory
|
||||
virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) {}
|
||||
|
||||
void ActivateController();
|
||||
Result Activate();
|
||||
Result Activate(u64 aruid);
|
||||
|
||||
void DeactivateController();
|
||||
|
||||
|
||||
@@ -86,6 +86,13 @@ public:
|
||||
Default = 3,
|
||||
};
|
||||
|
||||
enum class NpadRevision : u32 {
|
||||
Revision0 = 0,
|
||||
Revision1 = 1,
|
||||
Revision2 = 2,
|
||||
Revision3 = 3,
|
||||
};
|
||||
|
||||
void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set);
|
||||
Core::HID::NpadStyleTag GetSupportedStyleSet() const;
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ Result Controller_Palma::InitializePalma(const PalmaConnectionHandle& handle) {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
return InvalidPalmaHandle;
|
||||
}
|
||||
ActivateController();
|
||||
Activate();
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,220 +3,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core::Timing {
|
||||
struct EventType;
|
||||
}
|
||||
|
||||
namespace Service::SM {
|
||||
class ServiceManager;
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
enum class HidController : std::size_t {
|
||||
DebugPad,
|
||||
Touchscreen,
|
||||
Mouse,
|
||||
Keyboard,
|
||||
XPad,
|
||||
HomeButton,
|
||||
SleepButton,
|
||||
CaptureButton,
|
||||
InputDetector,
|
||||
UniquePad,
|
||||
NPad,
|
||||
Gesture,
|
||||
ConsoleSixAxisSensor,
|
||||
DebugMouse,
|
||||
Palma,
|
||||
|
||||
MaxControllers,
|
||||
};
|
||||
|
||||
class IAppletResource final : public ServiceFramework<IAppletResource> {
|
||||
public:
|
||||
explicit IAppletResource(Core::System& system_,
|
||||
KernelHelpers::ServiceContext& service_context_);
|
||||
~IAppletResource() override;
|
||||
|
||||
void ActivateController(HidController controller);
|
||||
void DeactivateController(HidController controller);
|
||||
|
||||
template <typename T>
|
||||
T& GetController(HidController controller) {
|
||||
return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T& GetController(HidController controller) const {
|
||||
return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
void MakeController(HidController controller, u8* shared_memory) {
|
||||
if constexpr (std::is_constructible_v<T, Core::System&, u8*>) {
|
||||
controllers[static_cast<std::size_t>(controller)] =
|
||||
std::make_unique<T>(system, shared_memory);
|
||||
} else {
|
||||
controllers[static_cast<std::size_t>(controller)] =
|
||||
std::make_unique<T>(system.HIDCore(), shared_memory);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void MakeControllerWithServiceContext(HidController controller, u8* shared_memory) {
|
||||
controllers[static_cast<std::size_t>(controller)] =
|
||||
std::make_unique<T>(system.HIDCore(), shared_memory, service_context);
|
||||
}
|
||||
|
||||
void GetSharedMemoryHandle(HLERequestContext& ctx);
|
||||
void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
||||
void UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
||||
void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
||||
void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
||||
|
||||
KernelHelpers::ServiceContext& service_context;
|
||||
|
||||
std::shared_ptr<Core::Timing::EventType> npad_update_event;
|
||||
std::shared_ptr<Core::Timing::EventType> default_update_event;
|
||||
std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event;
|
||||
std::shared_ptr<Core::Timing::EventType> motion_update_event;
|
||||
|
||||
std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)>
|
||||
controllers{};
|
||||
};
|
||||
|
||||
class Hid final : public ServiceFramework<Hid> {
|
||||
public:
|
||||
explicit Hid(Core::System& system_, std::shared_ptr<IAppletResource> applet_resource_);
|
||||
~Hid() override;
|
||||
|
||||
std::shared_ptr<IAppletResource> GetAppletResource();
|
||||
|
||||
private:
|
||||
void CreateAppletResource(HLERequestContext& ctx);
|
||||
void ActivateDebugPad(HLERequestContext& ctx);
|
||||
void ActivateTouchScreen(HLERequestContext& ctx);
|
||||
void ActivateMouse(HLERequestContext& ctx);
|
||||
void ActivateKeyboard(HLERequestContext& ctx);
|
||||
void SendKeyboardLockKeyEvent(HLERequestContext& ctx);
|
||||
void ActivateXpad(HLERequestContext& ctx);
|
||||
void GetXpadIDs(HLERequestContext& ctx);
|
||||
void ActivateSixAxisSensor(HLERequestContext& ctx);
|
||||
void DeactivateSixAxisSensor(HLERequestContext& ctx);
|
||||
void StartSixAxisSensor(HLERequestContext& ctx);
|
||||
void StopSixAxisSensor(HLERequestContext& ctx);
|
||||
void IsSixAxisSensorFusionEnabled(HLERequestContext& ctx);
|
||||
void EnableSixAxisSensorFusion(HLERequestContext& ctx);
|
||||
void SetSixAxisSensorFusionParameters(HLERequestContext& ctx);
|
||||
void GetSixAxisSensorFusionParameters(HLERequestContext& ctx);
|
||||
void ResetSixAxisSensorFusionParameters(HLERequestContext& ctx);
|
||||
void SetGyroscopeZeroDriftMode(HLERequestContext& ctx);
|
||||
void GetGyroscopeZeroDriftMode(HLERequestContext& ctx);
|
||||
void ResetGyroscopeZeroDriftMode(HLERequestContext& ctx);
|
||||
void IsSixAxisSensorAtRest(HLERequestContext& ctx);
|
||||
void IsFirmwareUpdateAvailableForSixAxisSensor(HLERequestContext& ctx);
|
||||
void EnableSixAxisSensorUnalteredPassthrough(HLERequestContext& ctx);
|
||||
void IsSixAxisSensorUnalteredPassthroughEnabled(HLERequestContext& ctx);
|
||||
void LoadSixAxisSensorCalibrationParameter(HLERequestContext& ctx);
|
||||
void GetSixAxisSensorIcInformation(HLERequestContext& ctx);
|
||||
void ResetIsSixAxisSensorDeviceNewlyAssigned(HLERequestContext& ctx);
|
||||
void ActivateGesture(HLERequestContext& ctx);
|
||||
void SetSupportedNpadStyleSet(HLERequestContext& ctx);
|
||||
void GetSupportedNpadStyleSet(HLERequestContext& ctx);
|
||||
void SetSupportedNpadIdType(HLERequestContext& ctx);
|
||||
void ActivateNpad(HLERequestContext& ctx);
|
||||
void DeactivateNpad(HLERequestContext& ctx);
|
||||
void AcquireNpadStyleSetUpdateEventHandle(HLERequestContext& ctx);
|
||||
void DisconnectNpad(HLERequestContext& ctx);
|
||||
void GetPlayerLedPattern(HLERequestContext& ctx);
|
||||
void ActivateNpadWithRevision(HLERequestContext& ctx);
|
||||
void SetNpadJoyHoldType(HLERequestContext& ctx);
|
||||
void GetNpadJoyHoldType(HLERequestContext& ctx);
|
||||
void SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx);
|
||||
void SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx);
|
||||
void SetNpadJoyAssignmentModeDual(HLERequestContext& ctx);
|
||||
void MergeSingleJoyAsDualJoy(HLERequestContext& ctx);
|
||||
void StartLrAssignmentMode(HLERequestContext& ctx);
|
||||
void StopLrAssignmentMode(HLERequestContext& ctx);
|
||||
void SetNpadHandheldActivationMode(HLERequestContext& ctx);
|
||||
void GetNpadHandheldActivationMode(HLERequestContext& ctx);
|
||||
void SwapNpadAssignment(HLERequestContext& ctx);
|
||||
void IsUnintendedHomeButtonInputProtectionEnabled(HLERequestContext& ctx);
|
||||
void EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx);
|
||||
void SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext& ctx);
|
||||
void SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx);
|
||||
void SetNpadCaptureButtonAssignment(HLERequestContext& ctx);
|
||||
void ClearNpadCaptureButtonAssignment(HLERequestContext& ctx);
|
||||
void GetVibrationDeviceInfo(HLERequestContext& ctx);
|
||||
void SendVibrationValue(HLERequestContext& ctx);
|
||||
void GetActualVibrationValue(HLERequestContext& ctx);
|
||||
void CreateActiveVibrationDeviceList(HLERequestContext& ctx);
|
||||
void PermitVibration(HLERequestContext& ctx);
|
||||
void IsVibrationPermitted(HLERequestContext& ctx);
|
||||
void SendVibrationValues(HLERequestContext& ctx);
|
||||
void SendVibrationGcErmCommand(HLERequestContext& ctx);
|
||||
void GetActualVibrationGcErmCommand(HLERequestContext& ctx);
|
||||
void BeginPermitVibrationSession(HLERequestContext& ctx);
|
||||
void EndPermitVibrationSession(HLERequestContext& ctx);
|
||||
void IsVibrationDeviceMounted(HLERequestContext& ctx);
|
||||
void ActivateConsoleSixAxisSensor(HLERequestContext& ctx);
|
||||
void StartConsoleSixAxisSensor(HLERequestContext& ctx);
|
||||
void StopConsoleSixAxisSensor(HLERequestContext& ctx);
|
||||
void ActivateSevenSixAxisSensor(HLERequestContext& ctx);
|
||||
void StartSevenSixAxisSensor(HLERequestContext& ctx);
|
||||
void StopSevenSixAxisSensor(HLERequestContext& ctx);
|
||||
void InitializeSevenSixAxisSensor(HLERequestContext& ctx);
|
||||
void FinalizeSevenSixAxisSensor(HLERequestContext& ctx);
|
||||
void ResetSevenSixAxisSensorTimestamp(HLERequestContext& ctx);
|
||||
void IsUsbFullKeyControllerEnabled(HLERequestContext& ctx);
|
||||
void GetPalmaConnectionHandle(HLERequestContext& ctx);
|
||||
void InitializePalma(HLERequestContext& ctx);
|
||||
void AcquirePalmaOperationCompleteEvent(HLERequestContext& ctx);
|
||||
void GetPalmaOperationInfo(HLERequestContext& ctx);
|
||||
void PlayPalmaActivity(HLERequestContext& ctx);
|
||||
void SetPalmaFrModeType(HLERequestContext& ctx);
|
||||
void ReadPalmaStep(HLERequestContext& ctx);
|
||||
void EnablePalmaStep(HLERequestContext& ctx);
|
||||
void ResetPalmaStep(HLERequestContext& ctx);
|
||||
void ReadPalmaApplicationSection(HLERequestContext& ctx);
|
||||
void WritePalmaApplicationSection(HLERequestContext& ctx);
|
||||
void ReadPalmaUniqueCode(HLERequestContext& ctx);
|
||||
void SetPalmaUniqueCodeInvalid(HLERequestContext& ctx);
|
||||
void WritePalmaActivityEntry(HLERequestContext& ctx);
|
||||
void WritePalmaRgbLedPatternEntry(HLERequestContext& ctx);
|
||||
void WritePalmaWaveEntry(HLERequestContext& ctx);
|
||||
void SetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx);
|
||||
void GetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx);
|
||||
void SuspendPalmaFeature(HLERequestContext& ctx);
|
||||
void GetPalmaOperationResult(HLERequestContext& ctx);
|
||||
void ReadPalmaPlayLog(HLERequestContext& ctx);
|
||||
void ResetPalmaPlayLog(HLERequestContext& ctx);
|
||||
void SetIsPalmaAllConnectable(HLERequestContext& ctx);
|
||||
void SetIsPalmaPairedConnectable(HLERequestContext& ctx);
|
||||
void PairPalma(HLERequestContext& ctx);
|
||||
void SetPalmaBoostMode(HLERequestContext& ctx);
|
||||
void CancelWritePalmaWaveEntry(HLERequestContext& ctx);
|
||||
void EnablePalmaBoostMode(HLERequestContext& ctx);
|
||||
void GetPalmaBluetoothAddress(HLERequestContext& ctx);
|
||||
void SetDisallowedPalmaConnection(HLERequestContext& ctx);
|
||||
void SetNpadCommunicationMode(HLERequestContext& ctx);
|
||||
void GetNpadCommunicationMode(HLERequestContext& ctx);
|
||||
void SetTouchScreenConfiguration(HLERequestContext& ctx);
|
||||
void IsFirmwareUpdateNeededForNotification(HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<IAppletResource> applet_resource;
|
||||
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
};
|
||||
|
||||
void LoopProcess(Core::System& system);
|
||||
|
||||
} // namespace Service::HID
|
||||
|
||||
159
src/core/hle/service/hid/hid_debug_server.cpp
Normal file
159
src/core/hle/service/hid/hid_debug_server.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "core/hle/service/hid/hid_debug_server.h"
|
||||
#include "core/hle/service/hid/resource_manager.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<ResourceManager> resource)
|
||||
: ServiceFramework{system_, "hid:dbg"}, resource_manager{resource} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "DeactivateDebugPad"},
|
||||
{1, nullptr, "SetDebugPadAutoPilotState"},
|
||||
{2, nullptr, "UnsetDebugPadAutoPilotState"},
|
||||
{10, nullptr, "DeactivateTouchScreen"},
|
||||
{11, nullptr, "SetTouchScreenAutoPilotState"},
|
||||
{12, nullptr, "UnsetTouchScreenAutoPilotState"},
|
||||
{13, nullptr, "GetTouchScreenConfiguration"},
|
||||
{14, nullptr, "ProcessTouchScreenAutoTune"},
|
||||
{15, nullptr, "ForceStopTouchScreenManagement"},
|
||||
{16, nullptr, "ForceRestartTouchScreenManagement"},
|
||||
{17, nullptr, "IsTouchScreenManaged"},
|
||||
{20, nullptr, "DeactivateMouse"},
|
||||
{21, nullptr, "SetMouseAutoPilotState"},
|
||||
{22, nullptr, "UnsetMouseAutoPilotState"},
|
||||
{25, nullptr, "SetDebugMouseAutoPilotState"},
|
||||
{26, nullptr, "UnsetDebugMouseAutoPilotState"},
|
||||
{30, nullptr, "DeactivateKeyboard"},
|
||||
{31, nullptr, "SetKeyboardAutoPilotState"},
|
||||
{32, nullptr, "UnsetKeyboardAutoPilotState"},
|
||||
{50, nullptr, "DeactivateXpad"},
|
||||
{51, nullptr, "SetXpadAutoPilotState"},
|
||||
{52, nullptr, "UnsetXpadAutoPilotState"},
|
||||
{53, nullptr, "DeactivateJoyXpad"},
|
||||
{60, nullptr, "ClearNpadSystemCommonPolicy"},
|
||||
{61, nullptr, "DeactivateNpad"},
|
||||
{62, nullptr, "ForceDisconnectNpad"},
|
||||
{91, nullptr, "DeactivateGesture"},
|
||||
{110, nullptr, "DeactivateHomeButton"},
|
||||
{111, nullptr, "SetHomeButtonAutoPilotState"},
|
||||
{112, nullptr, "UnsetHomeButtonAutoPilotState"},
|
||||
{120, nullptr, "DeactivateSleepButton"},
|
||||
{121, nullptr, "SetSleepButtonAutoPilotState"},
|
||||
{122, nullptr, "UnsetSleepButtonAutoPilotState"},
|
||||
{123, nullptr, "DeactivateInputDetector"},
|
||||
{130, nullptr, "DeactivateCaptureButton"},
|
||||
{131, nullptr, "SetCaptureButtonAutoPilotState"},
|
||||
{132, nullptr, "UnsetCaptureButtonAutoPilotState"},
|
||||
{133, nullptr, "SetShiftAccelerometerCalibrationValue"},
|
||||
{134, nullptr, "GetShiftAccelerometerCalibrationValue"},
|
||||
{135, nullptr, "SetShiftGyroscopeCalibrationValue"},
|
||||
{136, nullptr, "GetShiftGyroscopeCalibrationValue"},
|
||||
{140, nullptr, "DeactivateConsoleSixAxisSensor"},
|
||||
{141, nullptr, "GetConsoleSixAxisSensorSamplingFrequency"},
|
||||
{142, nullptr, "DeactivateSevenSixAxisSensor"},
|
||||
{143, nullptr, "GetConsoleSixAxisSensorCountStates"},
|
||||
{144, nullptr, "GetAccelerometerFsr"},
|
||||
{145, nullptr, "SetAccelerometerFsr"},
|
||||
{146, nullptr, "GetAccelerometerOdr"},
|
||||
{147, nullptr, "SetAccelerometerOdr"},
|
||||
{148, nullptr, "GetGyroscopeFsr"},
|
||||
{149, nullptr, "SetGyroscopeFsr"},
|
||||
{150, nullptr, "GetGyroscopeOdr"},
|
||||
{151, nullptr, "SetGyroscopeOdr"},
|
||||
{152, nullptr, "GetWhoAmI"},
|
||||
{201, nullptr, "ActivateFirmwareUpdate"},
|
||||
{202, nullptr, "DeactivateFirmwareUpdate"},
|
||||
{203, nullptr, "StartFirmwareUpdate"},
|
||||
{204, nullptr, "GetFirmwareUpdateStage"},
|
||||
{205, nullptr, "GetFirmwareVersion"},
|
||||
{206, nullptr, "GetDestinationFirmwareVersion"},
|
||||
{207, nullptr, "DiscardFirmwareInfoCacheForRevert"},
|
||||
{208, nullptr, "StartFirmwareUpdateForRevert"},
|
||||
{209, nullptr, "GetAvailableFirmwareVersionForRevert"},
|
||||
{210, nullptr, "IsFirmwareUpdatingDevice"},
|
||||
{211, nullptr, "StartFirmwareUpdateIndividual"},
|
||||
{215, nullptr, "SetUsbFirmwareForceUpdateEnabled"},
|
||||
{216, nullptr, "SetAllKuinaDevicesToFirmwareUpdateMode"},
|
||||
{221, nullptr, "UpdateControllerColor"},
|
||||
{222, nullptr, "ConnectUsbPadsAsync"},
|
||||
{223, nullptr, "DisconnectUsbPadsAsync"},
|
||||
{224, nullptr, "UpdateDesignInfo"},
|
||||
{225, nullptr, "GetUniquePadDriverState"},
|
||||
{226, nullptr, "GetSixAxisSensorDriverStates"},
|
||||
{227, nullptr, "GetRxPacketHistory"},
|
||||
{228, nullptr, "AcquireOperationEventHandle"},
|
||||
{229, nullptr, "ReadSerialFlash"},
|
||||
{230, nullptr, "WriteSerialFlash"},
|
||||
{231, nullptr, "GetOperationResult"},
|
||||
{232, nullptr, "EnableShipmentMode"},
|
||||
{233, nullptr, "ClearPairingInfo"},
|
||||
{234, nullptr, "GetUniquePadDeviceTypeSetInternal"},
|
||||
{235, nullptr, "EnableAnalogStickPower"},
|
||||
{236, nullptr, "RequestKuinaUartClockCal"},
|
||||
{237, nullptr, "GetKuinaUartClockCal"},
|
||||
{238, nullptr, "SetKuinaUartClockTrim"},
|
||||
{239, nullptr, "KuinaLoopbackTest"},
|
||||
{240, nullptr, "RequestBatteryVoltage"},
|
||||
{241, nullptr, "GetBatteryVoltage"},
|
||||
{242, nullptr, "GetUniquePadPowerInfo"},
|
||||
{243, nullptr, "RebootUniquePad"},
|
||||
{244, nullptr, "RequestKuinaFirmwareVersion"},
|
||||
{245, nullptr, "GetKuinaFirmwareVersion"},
|
||||
{246, nullptr, "GetVidPid"},
|
||||
{247, nullptr, "GetAnalogStickCalibrationValue"},
|
||||
{248, nullptr, "GetUniquePadIdsFull"},
|
||||
{249, nullptr, "ConnectUniquePad"},
|
||||
{250, nullptr, "IsVirtual"},
|
||||
{251, nullptr, "GetAnalogStickModuleParam"},
|
||||
{301, nullptr, "GetAbstractedPadHandles"},
|
||||
{302, nullptr, "GetAbstractedPadState"},
|
||||
{303, nullptr, "GetAbstractedPadsState"},
|
||||
{321, nullptr, "SetAutoPilotVirtualPadState"},
|
||||
{322, nullptr, "UnsetAutoPilotVirtualPadState"},
|
||||
{323, nullptr, "UnsetAllAutoPilotVirtualPadState"},
|
||||
{324, nullptr, "AttachHdlsWorkBuffer"},
|
||||
{325, nullptr, "ReleaseHdlsWorkBuffer"},
|
||||
{326, nullptr, "DumpHdlsNpadAssignmentState"},
|
||||
{327, nullptr, "DumpHdlsStates"},
|
||||
{328, nullptr, "ApplyHdlsNpadAssignmentState"},
|
||||
{329, nullptr, "ApplyHdlsStateList"},
|
||||
{330, nullptr, "AttachHdlsVirtualDevice"},
|
||||
{331, nullptr, "DetachHdlsVirtualDevice"},
|
||||
{332, nullptr, "SetHdlsState"},
|
||||
{350, nullptr, "AddRegisteredDevice"},
|
||||
{400, nullptr, "DisableExternalMcuOnNxDevice"},
|
||||
{401, nullptr, "DisableRailDeviceFiltering"},
|
||||
{402, nullptr, "EnableWiredPairing"},
|
||||
{403, nullptr, "EnableShipmentModeAutoClear"},
|
||||
{404, nullptr, "SetRailEnabled"},
|
||||
{500, nullptr, "SetFactoryInt"},
|
||||
{501, nullptr, "IsFactoryBootEnabled"},
|
||||
{550, nullptr, "SetAnalogStickModelDataTemporarily"},
|
||||
{551, nullptr, "GetAnalogStickModelData"},
|
||||
{552, nullptr, "ResetAnalogStickModelData"},
|
||||
{600, nullptr, "ConvertPadState"},
|
||||
{650, nullptr, "AddButtonPlayData"},
|
||||
{651, nullptr, "StartButtonPlayData"},
|
||||
{652, nullptr, "StopButtonPlayData"},
|
||||
{2000, nullptr, "DeactivateDigitizer"},
|
||||
{2001, nullptr, "SetDigitizerAutoPilotState"},
|
||||
{2002, nullptr, "UnsetDigitizerAutoPilotState"},
|
||||
{2002, nullptr, "ReloadFirmwareDebugSettings"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IHidDebugServer::~IHidDebugServer() = default;
|
||||
|
||||
std::shared_ptr<ResourceManager> IHidDebugServer::GetResourceManager() {
|
||||
resource_manager->Initialize();
|
||||
return resource_manager;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
||||
26
src/core/hle/service/hid/hid_debug_server.h
Normal file
26
src/core/hle/service/hid/hid_debug_server.h
Normal file
@@ -0,0 +1,26 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::HID {
|
||||
class ResourceManager;
|
||||
|
||||
class IHidDebugServer final : public ServiceFramework<IHidDebugServer> {
|
||||
public:
|
||||
explicit IHidDebugServer(Core::System& system_, std::shared_ptr<ResourceManager> resource);
|
||||
~IHidDebugServer() override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<ResourceManager> GetResourceManager();
|
||||
|
||||
std::shared_ptr<ResourceManager> resource_manager;
|
||||
};
|
||||
|
||||
} // namespace Service::HID
|
||||
99
src/core/hle/service/hid/hid_firmware_settings.cpp
Normal file
99
src/core/hle/service/hid/hid_firmware_settings.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "core/hle/service/hid/hid_firmware_settings.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
HidFirmwareSettings::HidFirmwareSettings() {
|
||||
LoadSettings(true);
|
||||
}
|
||||
|
||||
void HidFirmwareSettings::Reload() {
|
||||
LoadSettings(true);
|
||||
}
|
||||
|
||||
void HidFirmwareSettings::LoadSettings(bool reload_config) {
|
||||
if (is_initalized && !reload_config) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Use nn::settings::fwdbg::GetSettingsItemValue to load config values
|
||||
|
||||
is_debug_pad_enabled = true;
|
||||
is_device_managed = true;
|
||||
is_touch_i2c_managed = is_device_managed;
|
||||
is_future_devices_emulated = false;
|
||||
is_mcu_hardware_error_emulated = false;
|
||||
is_rail_enabled = true;
|
||||
is_firmware_update_failure_emulated = false;
|
||||
is_firmware_update_failure = {};
|
||||
is_ble_disabled = false;
|
||||
is_dscale_disabled = false;
|
||||
is_handheld_forced = true;
|
||||
features_per_id_disabled = {};
|
||||
is_touch_firmware_auto_update_disabled = false;
|
||||
is_initalized = true;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsDebugPadEnabled() {
|
||||
LoadSettings(false);
|
||||
return is_debug_pad_enabled;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsDeviceManaged() {
|
||||
LoadSettings(false);
|
||||
return is_device_managed;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsEmulateFutureDevice() {
|
||||
LoadSettings(false);
|
||||
return is_future_devices_emulated;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsTouchI2cManaged() {
|
||||
LoadSettings(false);
|
||||
return is_touch_i2c_managed;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsHandheldForced() {
|
||||
LoadSettings(false);
|
||||
return is_handheld_forced;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsRailEnabled() {
|
||||
LoadSettings(false);
|
||||
return is_rail_enabled;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsHardwareErrorEmulated() {
|
||||
LoadSettings(false);
|
||||
return is_mcu_hardware_error_emulated;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsBleDisabled() {
|
||||
LoadSettings(false);
|
||||
return is_ble_disabled;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsDscaleDisabled() {
|
||||
LoadSettings(false);
|
||||
return is_dscale_disabled;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsTouchAutoUpdateDisabled() {
|
||||
LoadSettings(false);
|
||||
return is_touch_firmware_auto_update_disabled;
|
||||
}
|
||||
|
||||
HidFirmwareSettings::FirmwareSetting HidFirmwareSettings::GetFirmwareUpdateFailure() {
|
||||
LoadSettings(false);
|
||||
return is_firmware_update_failure;
|
||||
}
|
||||
|
||||
HidFirmwareSettings::FeaturesPerId HidFirmwareSettings::FeaturesDisabledPerId() {
|
||||
LoadSettings(false);
|
||||
return features_per_id_disabled;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
||||
54
src/core/hle/service/hid/hid_firmware_settings.h
Normal file
54
src/core/hle/service/hid/hid_firmware_settings.h
Normal file
@@ -0,0 +1,54 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
/// Loads firmware config from nn::settings::fwdbg
|
||||
class HidFirmwareSettings {
|
||||
public:
|
||||
using FirmwareSetting = std::array<u8, 4>;
|
||||
using FeaturesPerId = std::array<bool, 0xA8>;
|
||||
|
||||
HidFirmwareSettings();
|
||||
|
||||
void Reload();
|
||||
void LoadSettings(bool reload_config);
|
||||
|
||||
bool IsDebugPadEnabled();
|
||||
bool IsDeviceManaged();
|
||||
bool IsEmulateFutureDevice();
|
||||
bool IsTouchI2cManaged();
|
||||
bool IsHandheldForced();
|
||||
bool IsRailEnabled();
|
||||
bool IsHardwareErrorEmulated();
|
||||
bool IsBleDisabled();
|
||||
bool IsDscaleDisabled();
|
||||
bool IsTouchAutoUpdateDisabled();
|
||||
|
||||
FirmwareSetting GetFirmwareUpdateFailure();
|
||||
FeaturesPerId FeaturesDisabledPerId();
|
||||
|
||||
private:
|
||||
bool is_initalized{};
|
||||
|
||||
// Debug settings
|
||||
bool is_debug_pad_enabled{};
|
||||
bool is_device_managed{};
|
||||
bool is_touch_i2c_managed{};
|
||||
bool is_future_devices_emulated{};
|
||||
bool is_mcu_hardware_error_emulated{};
|
||||
bool is_rail_enabled{};
|
||||
bool is_firmware_update_failure_emulated{};
|
||||
bool is_ble_disabled{};
|
||||
bool is_dscale_disabled{};
|
||||
bool is_handheld_forced{};
|
||||
bool is_touch_firmware_auto_update_disabled{};
|
||||
FirmwareSetting is_firmware_update_failure{};
|
||||
FeaturesPerId features_per_id_disabled{};
|
||||
};
|
||||
|
||||
} // namespace Service::HID
|
||||
2440
src/core/hle/service/hid/hid_server.cpp
Normal file
2440
src/core/hle/service/hid/hid_server.cpp
Normal file
File diff suppressed because it is too large
Load Diff
149
src/core/hle/service/hid/hid_server.h
Normal file
149
src/core/hle/service/hid/hid_server.h
Normal file
@@ -0,0 +1,149 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::HID {
|
||||
class ResourceManager;
|
||||
class HidFirmwareSettings;
|
||||
|
||||
class IHidServer final : public ServiceFramework<IHidServer> {
|
||||
public:
|
||||
explicit IHidServer(Core::System& system_, std::shared_ptr<ResourceManager> resource,
|
||||
std::shared_ptr<HidFirmwareSettings> settings);
|
||||
~IHidServer() override;
|
||||
|
||||
std::shared_ptr<ResourceManager> GetResourceManager();
|
||||
|
||||
private:
|
||||
void CreateAppletResource(HLERequestContext& ctx);
|
||||
void ActivateDebugPad(HLERequestContext& ctx);
|
||||
void ActivateTouchScreen(HLERequestContext& ctx);
|
||||
void ActivateMouse(HLERequestContext& ctx);
|
||||
void ActivateKeyboard(HLERequestContext& ctx);
|
||||
void SendKeyboardLockKeyEvent(HLERequestContext& ctx);
|
||||
void AcquireXpadIdEventHandle(HLERequestContext& ctx);
|
||||
void ReleaseXpadIdEventHandle(HLERequestContext& ctx);
|
||||
void ActivateXpad(HLERequestContext& ctx);
|
||||
void GetXpadIds(HLERequestContext& ctx);
|
||||
void ActivateJoyXpad(HLERequestContext& ctx);
|
||||
void GetJoyXpadLifoHandle(HLERequestContext& ctx);
|
||||
void GetJoyXpadIds(HLERequestContext& ctx);
|
||||
void ActivateSixAxisSensor(HLERequestContext& ctx);
|
||||
void DeactivateSixAxisSensor(HLERequestContext& ctx);
|
||||
void GetSixAxisSensorLifoHandle(HLERequestContext& ctx);
|
||||
void ActivateJoySixAxisSensor(HLERequestContext& ctx);
|
||||
void DeactivateJoySixAxisSensor(HLERequestContext& ctx);
|
||||
void GetJoySixAxisSensorLifoHandle(HLERequestContext& ctx);
|
||||
void StartSixAxisSensor(HLERequestContext& ctx);
|
||||
void StopSixAxisSensor(HLERequestContext& ctx);
|
||||
void IsSixAxisSensorFusionEnabled(HLERequestContext& ctx);
|
||||
void EnableSixAxisSensorFusion(HLERequestContext& ctx);
|
||||
void SetSixAxisSensorFusionParameters(HLERequestContext& ctx);
|
||||
void GetSixAxisSensorFusionParameters(HLERequestContext& ctx);
|
||||
void ResetSixAxisSensorFusionParameters(HLERequestContext& ctx);
|
||||
void SetGyroscopeZeroDriftMode(HLERequestContext& ctx);
|
||||
void GetGyroscopeZeroDriftMode(HLERequestContext& ctx);
|
||||
void ResetGyroscopeZeroDriftMode(HLERequestContext& ctx);
|
||||
void IsSixAxisSensorAtRest(HLERequestContext& ctx);
|
||||
void IsFirmwareUpdateAvailableForSixAxisSensor(HLERequestContext& ctx);
|
||||
void EnableSixAxisSensorUnalteredPassthrough(HLERequestContext& ctx);
|
||||
void IsSixAxisSensorUnalteredPassthroughEnabled(HLERequestContext& ctx);
|
||||
void LoadSixAxisSensorCalibrationParameter(HLERequestContext& ctx);
|
||||
void GetSixAxisSensorIcInformation(HLERequestContext& ctx);
|
||||
void ResetIsSixAxisSensorDeviceNewlyAssigned(HLERequestContext& ctx);
|
||||
void ActivateGesture(HLERequestContext& ctx);
|
||||
void SetSupportedNpadStyleSet(HLERequestContext& ctx);
|
||||
void GetSupportedNpadStyleSet(HLERequestContext& ctx);
|
||||
void SetSupportedNpadIdType(HLERequestContext& ctx);
|
||||
void ActivateNpad(HLERequestContext& ctx);
|
||||
void DeactivateNpad(HLERequestContext& ctx);
|
||||
void AcquireNpadStyleSetUpdateEventHandle(HLERequestContext& ctx);
|
||||
void DisconnectNpad(HLERequestContext& ctx);
|
||||
void GetPlayerLedPattern(HLERequestContext& ctx);
|
||||
void ActivateNpadWithRevision(HLERequestContext& ctx);
|
||||
void SetNpadJoyHoldType(HLERequestContext& ctx);
|
||||
void GetNpadJoyHoldType(HLERequestContext& ctx);
|
||||
void SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx);
|
||||
void SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx);
|
||||
void SetNpadJoyAssignmentModeDual(HLERequestContext& ctx);
|
||||
void MergeSingleJoyAsDualJoy(HLERequestContext& ctx);
|
||||
void StartLrAssignmentMode(HLERequestContext& ctx);
|
||||
void StopLrAssignmentMode(HLERequestContext& ctx);
|
||||
void SetNpadHandheldActivationMode(HLERequestContext& ctx);
|
||||
void GetNpadHandheldActivationMode(HLERequestContext& ctx);
|
||||
void SwapNpadAssignment(HLERequestContext& ctx);
|
||||
void IsUnintendedHomeButtonInputProtectionEnabled(HLERequestContext& ctx);
|
||||
void EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx);
|
||||
void SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext& ctx);
|
||||
void SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx);
|
||||
void SetNpadCaptureButtonAssignment(HLERequestContext& ctx);
|
||||
void ClearNpadCaptureButtonAssignment(HLERequestContext& ctx);
|
||||
void GetVibrationDeviceInfo(HLERequestContext& ctx);
|
||||
void SendVibrationValue(HLERequestContext& ctx);
|
||||
void GetActualVibrationValue(HLERequestContext& ctx);
|
||||
void CreateActiveVibrationDeviceList(HLERequestContext& ctx);
|
||||
void PermitVibration(HLERequestContext& ctx);
|
||||
void IsVibrationPermitted(HLERequestContext& ctx);
|
||||
void SendVibrationValues(HLERequestContext& ctx);
|
||||
void SendVibrationGcErmCommand(HLERequestContext& ctx);
|
||||
void GetActualVibrationGcErmCommand(HLERequestContext& ctx);
|
||||
void BeginPermitVibrationSession(HLERequestContext& ctx);
|
||||
void EndPermitVibrationSession(HLERequestContext& ctx);
|
||||
void IsVibrationDeviceMounted(HLERequestContext& ctx);
|
||||
void ActivateConsoleSixAxisSensor(HLERequestContext& ctx);
|
||||
void StartConsoleSixAxisSensor(HLERequestContext& ctx);
|
||||
void StopConsoleSixAxisSensor(HLERequestContext& ctx);
|
||||
void ActivateSevenSixAxisSensor(HLERequestContext& ctx);
|
||||
void StartSevenSixAxisSensor(HLERequestContext& ctx);
|
||||
void StopSevenSixAxisSensor(HLERequestContext& ctx);
|
||||
void InitializeSevenSixAxisSensor(HLERequestContext& ctx);
|
||||
void FinalizeSevenSixAxisSensor(HLERequestContext& ctx);
|
||||
void ResetSevenSixAxisSensorTimestamp(HLERequestContext& ctx);
|
||||
void IsUsbFullKeyControllerEnabled(HLERequestContext& ctx);
|
||||
void GetPalmaConnectionHandle(HLERequestContext& ctx);
|
||||
void InitializePalma(HLERequestContext& ctx);
|
||||
void AcquirePalmaOperationCompleteEvent(HLERequestContext& ctx);
|
||||
void GetPalmaOperationInfo(HLERequestContext& ctx);
|
||||
void PlayPalmaActivity(HLERequestContext& ctx);
|
||||
void SetPalmaFrModeType(HLERequestContext& ctx);
|
||||
void ReadPalmaStep(HLERequestContext& ctx);
|
||||
void EnablePalmaStep(HLERequestContext& ctx);
|
||||
void ResetPalmaStep(HLERequestContext& ctx);
|
||||
void ReadPalmaApplicationSection(HLERequestContext& ctx);
|
||||
void WritePalmaApplicationSection(HLERequestContext& ctx);
|
||||
void ReadPalmaUniqueCode(HLERequestContext& ctx);
|
||||
void SetPalmaUniqueCodeInvalid(HLERequestContext& ctx);
|
||||
void WritePalmaActivityEntry(HLERequestContext& ctx);
|
||||
void WritePalmaRgbLedPatternEntry(HLERequestContext& ctx);
|
||||
void WritePalmaWaveEntry(HLERequestContext& ctx);
|
||||
void SetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx);
|
||||
void GetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx);
|
||||
void SuspendPalmaFeature(HLERequestContext& ctx);
|
||||
void GetPalmaOperationResult(HLERequestContext& ctx);
|
||||
void ReadPalmaPlayLog(HLERequestContext& ctx);
|
||||
void ResetPalmaPlayLog(HLERequestContext& ctx);
|
||||
void SetIsPalmaAllConnectable(HLERequestContext& ctx);
|
||||
void SetIsPalmaPairedConnectable(HLERequestContext& ctx);
|
||||
void PairPalma(HLERequestContext& ctx);
|
||||
void SetPalmaBoostMode(HLERequestContext& ctx);
|
||||
void CancelWritePalmaWaveEntry(HLERequestContext& ctx);
|
||||
void EnablePalmaBoostMode(HLERequestContext& ctx);
|
||||
void GetPalmaBluetoothAddress(HLERequestContext& ctx);
|
||||
void SetDisallowedPalmaConnection(HLERequestContext& ctx);
|
||||
void SetNpadCommunicationMode(HLERequestContext& ctx);
|
||||
void GetNpadCommunicationMode(HLERequestContext& ctx);
|
||||
void SetTouchScreenConfiguration(HLERequestContext& ctx);
|
||||
void IsFirmwareUpdateNeededForNotification(HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<ResourceManager> resource_manager;
|
||||
std::shared_ptr<HidFirmwareSettings> firmware_settings;
|
||||
};
|
||||
|
||||
} // namespace Service::HID
|
||||
304
src/core/hle/service/hid/hid_system_server.cpp
Normal file
304
src/core/hle/service/hid/hid_system_server.cpp
Normal file
@@ -0,0 +1,304 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/service/hid/controllers/npad.h"
|
||||
#include "core/hle/service/hid/controllers/touchscreen.h"
|
||||
#include "core/hle/service/hid/errors.h"
|
||||
#include "core/hle/service/hid/hid_system_server.h"
|
||||
#include "core/hle/service/hid/resource_manager.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<ResourceManager> resource)
|
||||
: ServiceFramework{system_, "hid:sys"}, service_context{system_, service_name},
|
||||
resource_manager{resource} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{31, nullptr, "SendKeyboardLockKeyEvent"},
|
||||
{101, nullptr, "AcquireHomeButtonEventHandle"},
|
||||
{111, nullptr, "ActivateHomeButton"},
|
||||
{121, nullptr, "AcquireSleepButtonEventHandle"},
|
||||
{131, nullptr, "ActivateSleepButton"},
|
||||
{141, nullptr, "AcquireCaptureButtonEventHandle"},
|
||||
{151, nullptr, "ActivateCaptureButton"},
|
||||
{161, nullptr, "GetPlatformConfig"},
|
||||
{210, nullptr, "AcquireNfcDeviceUpdateEventHandle"},
|
||||
{211, nullptr, "GetNpadsWithNfc"},
|
||||
{212, nullptr, "AcquireNfcActivateEventHandle"},
|
||||
{213, nullptr, "ActivateNfc"},
|
||||
{214, nullptr, "GetXcdHandleForNpadWithNfc"},
|
||||
{215, nullptr, "IsNfcActivated"},
|
||||
{230, nullptr, "AcquireIrSensorEventHandle"},
|
||||
{231, nullptr, "ActivateIrSensor"},
|
||||
{232, nullptr, "GetIrSensorState"},
|
||||
{233, nullptr, "GetXcdHandleForNpadWithIrSensor"},
|
||||
{301, nullptr, "ActivateNpadSystem"},
|
||||
{303, &IHidSystemServer::ApplyNpadSystemCommonPolicy, "ApplyNpadSystemCommonPolicy"},
|
||||
{304, nullptr, "EnableAssigningSingleOnSlSrPress"},
|
||||
{305, nullptr, "DisableAssigningSingleOnSlSrPress"},
|
||||
{306, &IHidSystemServer::GetLastActiveNpad, "GetLastActiveNpad"},
|
||||
{307, nullptr, "GetNpadSystemExtStyle"},
|
||||
{308, nullptr, "ApplyNpadSystemCommonPolicyFull"},
|
||||
{309, nullptr, "GetNpadFullKeyGripColor"},
|
||||
{310, nullptr, "GetMaskedSupportedNpadStyleSet"},
|
||||
{311, nullptr, "SetNpadPlayerLedBlinkingDevice"},
|
||||
{312, nullptr, "SetSupportedNpadStyleSetAll"},
|
||||
{313, nullptr, "GetNpadCaptureButtonAssignment"},
|
||||
{314, nullptr, "GetAppletFooterUiType"},
|
||||
{315, nullptr, "GetAppletDetailedUiType"},
|
||||
{316, nullptr, "GetNpadInterfaceType"},
|
||||
{317, nullptr, "GetNpadLeftRightInterfaceType"},
|
||||
{318, nullptr, "HasBattery"},
|
||||
{319, nullptr, "HasLeftRightBattery"},
|
||||
{321, &IHidSystemServer::GetUniquePadsFromNpad, "GetUniquePadsFromNpad"},
|
||||
{322, nullptr, "GetIrSensorState"},
|
||||
{323, nullptr, "GetXcdHandleForNpadWithIrSensor"},
|
||||
{324, nullptr, "GetUniquePadButtonSet"},
|
||||
{325, nullptr, "GetUniquePadColor"},
|
||||
{326, nullptr, "GetUniquePadAppletDetailedUiType"},
|
||||
{327, nullptr, "GetAbstractedPadIdDataFromNpad"},
|
||||
{328, nullptr, "AttachAbstractedPadToNpad"},
|
||||
{329, nullptr, "DetachAbstractedPadAll"},
|
||||
{330, nullptr, "CheckAbstractedPadConnection"},
|
||||
{500, nullptr, "SetAppletResourceUserId"},
|
||||
{501, nullptr, "RegisterAppletResourceUserId"},
|
||||
{502, nullptr, "UnregisterAppletResourceUserId"},
|
||||
{503, nullptr, "EnableAppletToGetInput"},
|
||||
{504, nullptr, "SetAruidValidForVibration"},
|
||||
{505, nullptr, "EnableAppletToGetSixAxisSensor"},
|
||||
{506, nullptr, "EnableAppletToGetPadInput"},
|
||||
{507, nullptr, "EnableAppletToGetTouchScreen"},
|
||||
{510, nullptr, "SetVibrationMasterVolume"},
|
||||
{511, nullptr, "GetVibrationMasterVolume"},
|
||||
{512, nullptr, "BeginPermitVibrationSession"},
|
||||
{513, nullptr, "EndPermitVibrationSession"},
|
||||
{514, nullptr, "Unknown514"},
|
||||
{520, nullptr, "EnableHandheldHids"},
|
||||
{521, nullptr, "DisableHandheldHids"},
|
||||
{522, nullptr, "SetJoyConRailEnabled"},
|
||||
{523, nullptr, "IsJoyConRailEnabled"},
|
||||
{524, nullptr, "IsHandheldHidsEnabled"},
|
||||
{525, nullptr, "IsJoyConAttachedOnAllRail"},
|
||||
{540, nullptr, "AcquirePlayReportControllerUsageUpdateEvent"},
|
||||
{541, nullptr, "GetPlayReportControllerUsages"},
|
||||
{542, nullptr, "AcquirePlayReportRegisteredDeviceUpdateEvent"},
|
||||
{543, nullptr, "GetRegisteredDevicesOld"},
|
||||
{544, nullptr, "AcquireConnectionTriggerTimeoutEvent"},
|
||||
{545, nullptr, "SendConnectionTrigger"},
|
||||
{546, nullptr, "AcquireDeviceRegisteredEventForControllerSupport"},
|
||||
{547, nullptr, "GetAllowedBluetoothLinksCount"},
|
||||
{548, nullptr, "GetRegisteredDevices"},
|
||||
{549, nullptr, "GetConnectableRegisteredDevices"},
|
||||
{700, nullptr, "ActivateUniquePad"},
|
||||
{702, nullptr, "AcquireUniquePadConnectionEventHandle"},
|
||||
{703, nullptr, "GetUniquePadIds"},
|
||||
{751, &IHidSystemServer::AcquireJoyDetachOnBluetoothOffEventHandle, "AcquireJoyDetachOnBluetoothOffEventHandle"},
|
||||
{800, nullptr, "ListSixAxisSensorHandles"},
|
||||
{801, nullptr, "IsSixAxisSensorUserCalibrationSupported"},
|
||||
{802, nullptr, "ResetSixAxisSensorCalibrationValues"},
|
||||
{803, nullptr, "StartSixAxisSensorUserCalibration"},
|
||||
{804, nullptr, "CancelSixAxisSensorUserCalibration"},
|
||||
{805, nullptr, "GetUniquePadBluetoothAddress"},
|
||||
{806, nullptr, "DisconnectUniquePad"},
|
||||
{807, nullptr, "GetUniquePadType"},
|
||||
{808, nullptr, "GetUniquePadInterface"},
|
||||
{809, nullptr, "GetUniquePadSerialNumber"},
|
||||
{810, nullptr, "GetUniquePadControllerNumber"},
|
||||
{811, nullptr, "GetSixAxisSensorUserCalibrationStage"},
|
||||
{812, nullptr, "GetConsoleUniqueSixAxisSensorHandle"},
|
||||
{821, nullptr, "StartAnalogStickManualCalibration"},
|
||||
{822, nullptr, "RetryCurrentAnalogStickManualCalibrationStage"},
|
||||
{823, nullptr, "CancelAnalogStickManualCalibration"},
|
||||
{824, nullptr, "ResetAnalogStickManualCalibration"},
|
||||
{825, nullptr, "GetAnalogStickState"},
|
||||
{826, nullptr, "GetAnalogStickManualCalibrationStage"},
|
||||
{827, nullptr, "IsAnalogStickButtonPressed"},
|
||||
{828, nullptr, "IsAnalogStickInReleasePosition"},
|
||||
{829, nullptr, "IsAnalogStickInCircumference"},
|
||||
{830, nullptr, "SetNotificationLedPattern"},
|
||||
{831, nullptr, "SetNotificationLedPatternWithTimeout"},
|
||||
{832, nullptr, "PrepareHidsForNotificationWake"},
|
||||
{850, &IHidSystemServer::IsUsbFullKeyControllerEnabled, "IsUsbFullKeyControllerEnabled"},
|
||||
{851, nullptr, "EnableUsbFullKeyController"},
|
||||
{852, nullptr, "IsUsbConnected"},
|
||||
{870, nullptr, "IsHandheldButtonPressedOnConsoleMode"},
|
||||
{900, nullptr, "ActivateInputDetector"},
|
||||
{901, nullptr, "NotifyInputDetector"},
|
||||
{1000, nullptr, "InitializeFirmwareUpdate"},
|
||||
{1001, nullptr, "GetFirmwareVersion"},
|
||||
{1002, nullptr, "GetAvailableFirmwareVersion"},
|
||||
{1003, nullptr, "IsFirmwareUpdateAvailable"},
|
||||
{1004, nullptr, "CheckFirmwareUpdateRequired"},
|
||||
{1005, nullptr, "StartFirmwareUpdate"},
|
||||
{1006, nullptr, "AbortFirmwareUpdate"},
|
||||
{1007, nullptr, "GetFirmwareUpdateState"},
|
||||
{1008, nullptr, "ActivateAudioControl"},
|
||||
{1009, nullptr, "AcquireAudioControlEventHandle"},
|
||||
{1010, nullptr, "GetAudioControlStates"},
|
||||
{1011, nullptr, "DeactivateAudioControl"},
|
||||
{1050, nullptr, "IsSixAxisSensorAccurateUserCalibrationSupported"},
|
||||
{1051, nullptr, "StartSixAxisSensorAccurateUserCalibration"},
|
||||
{1052, nullptr, "CancelSixAxisSensorAccurateUserCalibration"},
|
||||
{1053, nullptr, "GetSixAxisSensorAccurateUserCalibrationState"},
|
||||
{1100, nullptr, "GetHidbusSystemServiceObject"},
|
||||
{1120, nullptr, "SetFirmwareHotfixUpdateSkipEnabled"},
|
||||
{1130, nullptr, "InitializeUsbFirmwareUpdate"},
|
||||
{1131, nullptr, "FinalizeUsbFirmwareUpdate"},
|
||||
{1132, nullptr, "CheckUsbFirmwareUpdateRequired"},
|
||||
{1133, nullptr, "StartUsbFirmwareUpdate"},
|
||||
{1134, nullptr, "GetUsbFirmwareUpdateState"},
|
||||
{1150, nullptr, "SetTouchScreenMagnification"},
|
||||
{1151, nullptr, "GetTouchScreenFirmwareVersion"},
|
||||
{1152, nullptr, "SetTouchScreenDefaultConfiguration"},
|
||||
{1153, &IHidSystemServer::GetTouchScreenDefaultConfiguration, "GetTouchScreenDefaultConfiguration"},
|
||||
{1154, nullptr, "IsFirmwareAvailableForNotification"},
|
||||
{1155, nullptr, "SetForceHandheldStyleVibration"},
|
||||
{1156, nullptr, "SendConnectionTriggerWithoutTimeoutEvent"},
|
||||
{1157, nullptr, "CancelConnectionTrigger"},
|
||||
{1200, nullptr, "IsButtonConfigSupported"},
|
||||
{1201, nullptr, "IsButtonConfigEmbeddedSupported"},
|
||||
{1202, nullptr, "DeleteButtonConfig"},
|
||||
{1203, nullptr, "DeleteButtonConfigEmbedded"},
|
||||
{1204, nullptr, "SetButtonConfigEnabled"},
|
||||
{1205, nullptr, "SetButtonConfigEmbeddedEnabled"},
|
||||
{1206, nullptr, "IsButtonConfigEnabled"},
|
||||
{1207, nullptr, "IsButtonConfigEmbeddedEnabled"},
|
||||
{1208, nullptr, "SetButtonConfigEmbedded"},
|
||||
{1209, nullptr, "SetButtonConfigFull"},
|
||||
{1210, nullptr, "SetButtonConfigLeft"},
|
||||
{1211, nullptr, "SetButtonConfigRight"},
|
||||
{1212, nullptr, "GetButtonConfigEmbedded"},
|
||||
{1213, nullptr, "GetButtonConfigFull"},
|
||||
{1214, nullptr, "GetButtonConfigLeft"},
|
||||
{1215, nullptr, "GetButtonConfigRight"},
|
||||
{1250, nullptr, "IsCustomButtonConfigSupported"},
|
||||
{1251, nullptr, "IsDefaultButtonConfigEmbedded"},
|
||||
{1252, nullptr, "IsDefaultButtonConfigFull"},
|
||||
{1253, nullptr, "IsDefaultButtonConfigLeft"},
|
||||
{1254, nullptr, "IsDefaultButtonConfigRight"},
|
||||
{1255, nullptr, "IsButtonConfigStorageEmbeddedEmpty"},
|
||||
{1256, nullptr, "IsButtonConfigStorageFullEmpty"},
|
||||
{1257, nullptr, "IsButtonConfigStorageLeftEmpty"},
|
||||
{1258, nullptr, "IsButtonConfigStorageRightEmpty"},
|
||||
{1259, nullptr, "GetButtonConfigStorageEmbeddedDeprecated"},
|
||||
{1260, nullptr, "GetButtonConfigStorageFullDeprecated"},
|
||||
{1261, nullptr, "GetButtonConfigStorageLeftDeprecated"},
|
||||
{1262, nullptr, "GetButtonConfigStorageRightDeprecated"},
|
||||
{1263, nullptr, "SetButtonConfigStorageEmbeddedDeprecated"},
|
||||
{1264, nullptr, "SetButtonConfigStorageFullDeprecated"},
|
||||
{1265, nullptr, "SetButtonConfigStorageLeftDeprecated"},
|
||||
{1266, nullptr, "SetButtonConfigStorageRightDeprecated"},
|
||||
{1267, nullptr, "DeleteButtonConfigStorageEmbedded"},
|
||||
{1268, nullptr, "DeleteButtonConfigStorageFull"},
|
||||
{1269, nullptr, "DeleteButtonConfigStorageLeft"},
|
||||
{1270, nullptr, "DeleteButtonConfigStorageRight"},
|
||||
{1271, nullptr, "IsUsingCustomButtonConfig"},
|
||||
{1272, nullptr, "IsAnyCustomButtonConfigEnabled"},
|
||||
{1273, nullptr, "SetAllCustomButtonConfigEnabled"},
|
||||
{1274, nullptr, "SetDefaultButtonConfig"},
|
||||
{1275, nullptr, "SetAllDefaultButtonConfig"},
|
||||
{1276, nullptr, "SetHidButtonConfigEmbedded"},
|
||||
{1277, nullptr, "SetHidButtonConfigFull"},
|
||||
{1278, nullptr, "SetHidButtonConfigLeft"},
|
||||
{1279, nullptr, "SetHidButtonConfigRight"},
|
||||
{1280, nullptr, "GetHidButtonConfigEmbedded"},
|
||||
{1281, nullptr, "GetHidButtonConfigFull"},
|
||||
{1282, nullptr, "GetHidButtonConfigLeft"},
|
||||
{1283, nullptr, "GetHidButtonConfigRight"},
|
||||
{1284, nullptr, "GetButtonConfigStorageEmbedded"},
|
||||
{1285, nullptr, "GetButtonConfigStorageFull"},
|
||||
{1286, nullptr, "GetButtonConfigStorageLeft"},
|
||||
{1287, nullptr, "GetButtonConfigStorageRight"},
|
||||
{1288, nullptr, "SetButtonConfigStorageEmbedded"},
|
||||
{1289, nullptr, "SetButtonConfigStorageFull"},
|
||||
{1290, nullptr, "DeleteButtonConfigStorageRight"},
|
||||
{1291, nullptr, "DeleteButtonConfigStorageRight"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
|
||||
joy_detach_event = service_context.CreateEvent("HidSys::JoyDetachEvent");
|
||||
}
|
||||
|
||||
IHidSystemServer::~IHidSystemServer() {
|
||||
service_context.CloseEvent(joy_detach_event);
|
||||
};
|
||||
|
||||
void IHidSystemServer::ApplyNpadSystemCommonPolicy(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_HID, "called");
|
||||
|
||||
GetResourceManager()
|
||||
->GetController<Controller_NPad>(HidController::NPad)
|
||||
.ApplyNpadSystemCommonPolicy();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IHidSystemServer::GetLastActiveNpad(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(system.HIDCore().GetLastActiveController());
|
||||
}
|
||||
|
||||
void IHidSystemServer::GetUniquePadsFromNpad(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
|
||||
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called, npad_id_type={}", npad_id_type);
|
||||
|
||||
const std::vector<Core::HID::UniquePadId> unique_pads{};
|
||||
|
||||
ctx.WriteBuffer(unique_pads);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(static_cast<u32>(unique_pads.size()));
|
||||
}
|
||||
|
||||
void IHidSystemServer::AcquireJoyDetachOnBluetoothOffEventHandle(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(joy_detach_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void IHidSystemServer::IsUsbFullKeyControllerEnabled(HLERequestContext& ctx) {
|
||||
const bool is_enabled = false;
|
||||
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called, is_enabled={}", is_enabled);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(is_enabled);
|
||||
}
|
||||
|
||||
void IHidSystemServer::GetTouchScreenDefaultConfiguration(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
|
||||
Core::HID::TouchScreenConfigurationForNx touchscreen_config{
|
||||
.mode = Core::HID::TouchScreenModeForNx::Finger,
|
||||
};
|
||||
|
||||
if (touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Heat2 &&
|
||||
touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Finger) {
|
||||
touchscreen_config.mode = Core::HID::TouchScreenModeForNx::UseSystemSetting;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw(touchscreen_config);
|
||||
}
|
||||
|
||||
std::shared_ptr<ResourceManager> IHidSystemServer::GetResourceManager() {
|
||||
resource_manager->Initialize();
|
||||
return resource_manager;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
||||
40
src/core/hle/service/hid/hid_system_server.h
Normal file
40
src/core/hle/service/hid/hid_system_server.h
Normal file
@@ -0,0 +1,40 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
class KEvent;
|
||||
}
|
||||
|
||||
namespace Service::HID {
|
||||
class ResourceManager;
|
||||
|
||||
class IHidSystemServer final : public ServiceFramework<IHidSystemServer> {
|
||||
public:
|
||||
explicit IHidSystemServer(Core::System& system_, std::shared_ptr<ResourceManager> resource);
|
||||
~IHidSystemServer() override;
|
||||
|
||||
private:
|
||||
void ApplyNpadSystemCommonPolicy(HLERequestContext& ctx);
|
||||
void GetLastActiveNpad(HLERequestContext& ctx);
|
||||
void GetUniquePadsFromNpad(HLERequestContext& ctx);
|
||||
void AcquireJoyDetachOnBluetoothOffEventHandle(HLERequestContext& ctx);
|
||||
void IsUsbFullKeyControllerEnabled(HLERequestContext& ctx);
|
||||
void GetTouchScreenDefaultConfiguration(HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<ResourceManager> GetResourceManager();
|
||||
|
||||
Kernel::KEvent* joy_detach_event;
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
std::shared_ptr<ResourceManager> resource_manager;
|
||||
};
|
||||
|
||||
} // namespace Service::HID
|
||||
@@ -3,15 +3,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hid/irs_types.h"
|
||||
#include "core/hle/service/hid/irsensor/processor_base.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Core::HID {
|
||||
class EmulatedController;
|
||||
} // namespace Core::HID
|
||||
|
||||
184
src/core/hle/service/hid/resource_manager.cpp
Normal file
184
src/core/hle/service/hid/resource_manager.cpp
Normal file
@@ -0,0 +1,184 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/kernel/k_shared_memory.h"
|
||||
#include "core/hle/service/hid/resource_manager.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
|
||||
#include "core/hle/service/hid/controllers/console_sixaxis.h"
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
#include "core/hle/service/hid/controllers/debug_pad.h"
|
||||
#include "core/hle/service/hid/controllers/gesture.h"
|
||||
#include "core/hle/service/hid/controllers/keyboard.h"
|
||||
#include "core/hle/service/hid/controllers/mouse.h"
|
||||
#include "core/hle/service/hid/controllers/npad.h"
|
||||
#include "core/hle/service/hid/controllers/palma.h"
|
||||
#include "core/hle/service/hid/controllers/stubbed.h"
|
||||
#include "core/hle/service/hid/controllers/touchscreen.h"
|
||||
#include "core/hle/service/hid/controllers/xpad.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
// Updating period for each HID device.
|
||||
// Period time is obtained by measuring the number of samples in a second on HW using a homebrew
|
||||
// Correct npad_update_ns is 4ms this is overclocked to lower input lag
|
||||
constexpr auto npad_update_ns = std::chrono::nanoseconds{1 * 1000 * 1000}; // (1ms, 1000Hz)
|
||||
constexpr auto default_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 1000Hz)
|
||||
constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz)
|
||||
constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz)
|
||||
|
||||
ResourceManager::ResourceManager(Core::System& system_)
|
||||
: system{system_}, service_context{system_, "hid"} {}
|
||||
|
||||
ResourceManager::~ResourceManager() = default;
|
||||
|
||||
void ResourceManager::Initialize() {
|
||||
if (is_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
u8* shared_memory = system.Kernel().GetHidSharedMem().GetPointer();
|
||||
MakeController<Controller_DebugPad>(HidController::DebugPad, shared_memory);
|
||||
MakeController<Controller_Touchscreen>(HidController::Touchscreen, shared_memory);
|
||||
MakeController<Controller_Mouse>(HidController::Mouse, shared_memory);
|
||||
MakeController<Controller_Keyboard>(HidController::Keyboard, shared_memory);
|
||||
MakeController<Controller_XPad>(HidController::XPad, shared_memory);
|
||||
MakeController<Controller_Stubbed>(HidController::HomeButton, shared_memory);
|
||||
MakeController<Controller_Stubbed>(HidController::SleepButton, shared_memory);
|
||||
MakeController<Controller_Stubbed>(HidController::CaptureButton, shared_memory);
|
||||
MakeController<Controller_Stubbed>(HidController::InputDetector, shared_memory);
|
||||
MakeController<Controller_Stubbed>(HidController::UniquePad, shared_memory);
|
||||
MakeControllerWithServiceContext<Controller_NPad>(HidController::NPad, shared_memory);
|
||||
MakeController<Controller_Gesture>(HidController::Gesture, shared_memory);
|
||||
MakeController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor, shared_memory);
|
||||
MakeController<Controller_Stubbed>(HidController::DebugMouse, shared_memory);
|
||||
MakeControllerWithServiceContext<Controller_Palma>(HidController::Palma, shared_memory);
|
||||
|
||||
// Homebrew doesn't try to activate some controllers, so we activate them by default
|
||||
GetController<Controller_NPad>(HidController::NPad).Activate();
|
||||
GetController<Controller_Touchscreen>(HidController::Touchscreen).Activate();
|
||||
|
||||
GetController<Controller_Stubbed>(HidController::HomeButton).SetCommonHeaderOffset(0x4C00);
|
||||
GetController<Controller_Stubbed>(HidController::SleepButton).SetCommonHeaderOffset(0x4E00);
|
||||
GetController<Controller_Stubbed>(HidController::CaptureButton).SetCommonHeaderOffset(0x5000);
|
||||
GetController<Controller_Stubbed>(HidController::InputDetector).SetCommonHeaderOffset(0x5200);
|
||||
GetController<Controller_Stubbed>(HidController::UniquePad).SetCommonHeaderOffset(0x5A00);
|
||||
GetController<Controller_Stubbed>(HidController::DebugMouse).SetCommonHeaderOffset(0x3DC00);
|
||||
|
||||
system.HIDCore().ReloadInputDevices();
|
||||
is_initialized = true;
|
||||
}
|
||||
|
||||
void ResourceManager::UpdateControllers(std::uintptr_t user_data,
|
||||
std::chrono::nanoseconds ns_late) {
|
||||
auto& core_timing = system.CoreTiming();
|
||||
|
||||
for (const auto& controller : controllers) {
|
||||
// Keyboard has it's own update event
|
||||
if (controller == controllers[static_cast<size_t>(HidController::Keyboard)]) {
|
||||
continue;
|
||||
}
|
||||
// Mouse has it's own update event
|
||||
if (controller == controllers[static_cast<size_t>(HidController::Mouse)]) {
|
||||
continue;
|
||||
}
|
||||
// Npad has it's own update event
|
||||
if (controller == controllers[static_cast<size_t>(HidController::NPad)]) {
|
||||
continue;
|
||||
}
|
||||
controller->OnUpdate(core_timing);
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceManager::UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
|
||||
auto& core_timing = system.CoreTiming();
|
||||
|
||||
controllers[static_cast<size_t>(HidController::NPad)]->OnUpdate(core_timing);
|
||||
}
|
||||
|
||||
void ResourceManager::UpdateMouseKeyboard(std::uintptr_t user_data,
|
||||
std::chrono::nanoseconds ns_late) {
|
||||
auto& core_timing = system.CoreTiming();
|
||||
|
||||
controllers[static_cast<size_t>(HidController::Mouse)]->OnUpdate(core_timing);
|
||||
controllers[static_cast<size_t>(HidController::Keyboard)]->OnUpdate(core_timing);
|
||||
}
|
||||
|
||||
void ResourceManager::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
|
||||
auto& core_timing = system.CoreTiming();
|
||||
|
||||
controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate(core_timing);
|
||||
}
|
||||
|
||||
IAppletResource::IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource)
|
||||
: ServiceFramework{system_, "IAppletResource"} {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
|
||||
resource->Initialize();
|
||||
|
||||
// Register update callbacks
|
||||
npad_update_event = Core::Timing::CreateEvent(
|
||||
"HID::UpdatePadCallback",
|
||||
[this, resource](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)
|
||||
-> std::optional<std::chrono::nanoseconds> {
|
||||
const auto guard = LockService();
|
||||
resource->UpdateNpad(user_data, ns_late);
|
||||
return std::nullopt;
|
||||
});
|
||||
default_update_event = Core::Timing::CreateEvent(
|
||||
"HID::UpdateDefaultCallback",
|
||||
[this, resource](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)
|
||||
-> std::optional<std::chrono::nanoseconds> {
|
||||
const auto guard = LockService();
|
||||
resource->UpdateControllers(user_data, ns_late);
|
||||
return std::nullopt;
|
||||
});
|
||||
mouse_keyboard_update_event = Core::Timing::CreateEvent(
|
||||
"HID::UpdateMouseKeyboardCallback",
|
||||
[this, resource](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)
|
||||
-> std::optional<std::chrono::nanoseconds> {
|
||||
const auto guard = LockService();
|
||||
resource->UpdateMouseKeyboard(user_data, ns_late);
|
||||
return std::nullopt;
|
||||
});
|
||||
motion_update_event = Core::Timing::CreateEvent(
|
||||
"HID::UpdateMotionCallback",
|
||||
[this, resource](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)
|
||||
-> std::optional<std::chrono::nanoseconds> {
|
||||
const auto guard = LockService();
|
||||
resource->UpdateMotion(user_data, ns_late);
|
||||
return std::nullopt;
|
||||
});
|
||||
|
||||
system.CoreTiming().ScheduleLoopingEvent(npad_update_ns, npad_update_ns, npad_update_event);
|
||||
system.CoreTiming().ScheduleLoopingEvent(default_update_ns, default_update_ns,
|
||||
default_update_event);
|
||||
system.CoreTiming().ScheduleLoopingEvent(mouse_keyboard_update_ns, mouse_keyboard_update_ns,
|
||||
mouse_keyboard_update_event);
|
||||
system.CoreTiming().ScheduleLoopingEvent(motion_update_ns, motion_update_ns,
|
||||
motion_update_event);
|
||||
}
|
||||
|
||||
IAppletResource::~IAppletResource() {
|
||||
system.CoreTiming().UnscheduleEvent(npad_update_event, 0);
|
||||
system.CoreTiming().UnscheduleEvent(default_update_event, 0);
|
||||
system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event, 0);
|
||||
system.CoreTiming().UnscheduleEvent(motion_update_event, 0);
|
||||
}
|
||||
|
||||
void IAppletResource::GetSharedMemoryHandle(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(&system.Kernel().GetHidSharedMem());
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
||||
104
src/core/hle/service/hid/resource_manager.h
Normal file
104
src/core/hle/service/hid/resource_manager.h
Normal file
@@ -0,0 +1,104 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core::Timing {
|
||||
struct EventType;
|
||||
}
|
||||
|
||||
namespace Core::HID {
|
||||
class HIDCore;
|
||||
}
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
enum class HidController : std::size_t {
|
||||
DebugPad,
|
||||
Touchscreen,
|
||||
Mouse,
|
||||
Keyboard,
|
||||
XPad,
|
||||
HomeButton,
|
||||
SleepButton,
|
||||
CaptureButton,
|
||||
InputDetector,
|
||||
UniquePad,
|
||||
NPad,
|
||||
Gesture,
|
||||
ConsoleSixAxisSensor,
|
||||
DebugMouse,
|
||||
Palma,
|
||||
|
||||
MaxControllers,
|
||||
};
|
||||
class ResourceManager {
|
||||
public:
|
||||
explicit ResourceManager(Core::System& system_);
|
||||
~ResourceManager();
|
||||
|
||||
template <typename T>
|
||||
T& GetController(HidController controller) {
|
||||
return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T& GetController(HidController controller) const {
|
||||
return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
|
||||
}
|
||||
|
||||
void Initialize();
|
||||
|
||||
void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
||||
void UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
||||
void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
||||
void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
void MakeController(HidController controller, u8* shared_memory) {
|
||||
if constexpr (std::is_constructible_v<T, Core::System&, u8*>) {
|
||||
controllers[static_cast<std::size_t>(controller)] =
|
||||
std::make_unique<T>(system, shared_memory);
|
||||
} else {
|
||||
controllers[static_cast<std::size_t>(controller)] =
|
||||
std::make_unique<T>(system.HIDCore(), shared_memory);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void MakeControllerWithServiceContext(HidController controller, u8* shared_memory) {
|
||||
controllers[static_cast<std::size_t>(controller)] =
|
||||
std::make_unique<T>(system.HIDCore(), shared_memory, service_context);
|
||||
}
|
||||
|
||||
bool is_initialized{false};
|
||||
std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)>
|
||||
controllers{};
|
||||
|
||||
Core::System& system;
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
};
|
||||
|
||||
class IAppletResource final : public ServiceFramework<IAppletResource> {
|
||||
public:
|
||||
explicit IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource);
|
||||
~IAppletResource() override;
|
||||
|
||||
private:
|
||||
void GetSharedMemoryHandle(HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<Core::Timing::EventType> npad_update_event;
|
||||
std::shared_ptr<Core::Timing::EventType> default_update_event;
|
||||
std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event;
|
||||
std::shared_ptr<Core::Timing::EventType> motion_update_event;
|
||||
};
|
||||
|
||||
} // namespace Service::HID
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
namespace Service::android {
|
||||
|
||||
struct GraphicBuffer;
|
||||
class GraphicBuffer;
|
||||
|
||||
class BufferItem final {
|
||||
public:
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/BufferQueueConsumer.cpp
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/service/nvdrv/core/nvmap.h"
|
||||
#include "core/hle/service/nvnflinger/buffer_item.h"
|
||||
#include "core/hle/service/nvnflinger/buffer_queue_consumer.h"
|
||||
#include "core/hle/service/nvnflinger/buffer_queue_core.h"
|
||||
@@ -14,9 +13,8 @@
|
||||
|
||||
namespace Service::android {
|
||||
|
||||
BufferQueueConsumer::BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_,
|
||||
Service::Nvidia::NvCore::NvMap& nvmap_)
|
||||
: core{std::move(core_)}, slots{core->slots}, nvmap(nvmap_) {}
|
||||
BufferQueueConsumer::BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_)
|
||||
: core{std::move(core_)}, slots{core->slots} {}
|
||||
|
||||
BufferQueueConsumer::~BufferQueueConsumer() = default;
|
||||
|
||||
@@ -136,8 +134,6 @@ Status BufferQueueConsumer::ReleaseBuffer(s32 slot, u64 frame_number, const Fenc
|
||||
|
||||
slots[slot].buffer_state = BufferState::Free;
|
||||
|
||||
nvmap.FreeHandle(slots[slot].graphic_buffer->BufferId(), true);
|
||||
|
||||
listener = core->connected_producer_listener;
|
||||
|
||||
LOG_DEBUG(Service_Nvnflinger, "releasing slot {}", slot);
|
||||
@@ -175,6 +171,25 @@ Status BufferQueueConsumer::Connect(std::shared_ptr<IConsumerListener> consumer_
|
||||
return Status::NoError;
|
||||
}
|
||||
|
||||
Status BufferQueueConsumer::Disconnect() {
|
||||
LOG_DEBUG(Service_Nvnflinger, "called");
|
||||
|
||||
std::scoped_lock lock{core->mutex};
|
||||
|
||||
if (core->consumer_listener == nullptr) {
|
||||
LOG_ERROR(Service_Nvnflinger, "no consumer is connected");
|
||||
return Status::BadValue;
|
||||
}
|
||||
|
||||
core->is_abandoned = true;
|
||||
core->consumer_listener = nullptr;
|
||||
core->queue.clear();
|
||||
core->FreeAllBuffersLocked();
|
||||
core->SignalDequeueCondition();
|
||||
|
||||
return Status::NoError;
|
||||
}
|
||||
|
||||
Status BufferQueueConsumer::GetReleasedBuffers(u64* out_slot_mask) {
|
||||
if (out_slot_mask == nullptr) {
|
||||
LOG_ERROR(Service_Nvnflinger, "out_slot_mask may not be nullptr");
|
||||
|
||||
@@ -13,10 +13,6 @@
|
||||
#include "core/hle/service/nvnflinger/buffer_queue_defs.h"
|
||||
#include "core/hle/service/nvnflinger/status.h"
|
||||
|
||||
namespace Service::Nvidia::NvCore {
|
||||
class NvMap;
|
||||
} // namespace Service::Nvidia::NvCore
|
||||
|
||||
namespace Service::android {
|
||||
|
||||
class BufferItem;
|
||||
@@ -25,19 +21,18 @@ class IConsumerListener;
|
||||
|
||||
class BufferQueueConsumer final {
|
||||
public:
|
||||
explicit BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_,
|
||||
Service::Nvidia::NvCore::NvMap& nvmap_);
|
||||
explicit BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_);
|
||||
~BufferQueueConsumer();
|
||||
|
||||
Status AcquireBuffer(BufferItem* out_buffer, std::chrono::nanoseconds expected_present);
|
||||
Status ReleaseBuffer(s32 slot, u64 frame_number, const Fence& release_fence);
|
||||
Status Connect(std::shared_ptr<IConsumerListener> consumer_listener, bool controlled_by_app);
|
||||
Status Disconnect();
|
||||
Status GetReleasedBuffers(u64* out_slot_mask);
|
||||
|
||||
private:
|
||||
std::shared_ptr<BufferQueueCore> core;
|
||||
BufferQueueDefs::SlotsType& slots;
|
||||
Service::Nvidia::NvCore::NvMap& nvmap;
|
||||
};
|
||||
|
||||
} // namespace Service::android
|
||||
|
||||
@@ -14,24 +14,12 @@ BufferQueueCore::BufferQueueCore() = default;
|
||||
|
||||
BufferQueueCore::~BufferQueueCore() = default;
|
||||
|
||||
void BufferQueueCore::NotifyShutdown() {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
is_shutting_down = true;
|
||||
|
||||
SignalDequeueCondition();
|
||||
}
|
||||
|
||||
void BufferQueueCore::SignalDequeueCondition() {
|
||||
dequeue_possible.store(true);
|
||||
dequeue_condition.notify_all();
|
||||
}
|
||||
|
||||
bool BufferQueueCore::WaitForDequeueCondition(std::unique_lock<std::mutex>& lk) {
|
||||
if (is_shutting_down) {
|
||||
return false;
|
||||
}
|
||||
|
||||
dequeue_condition.wait(lk, [&] { return dequeue_possible.load(); });
|
||||
dequeue_possible.store(false);
|
||||
|
||||
|
||||
@@ -34,8 +34,6 @@ public:
|
||||
BufferQueueCore();
|
||||
~BufferQueueCore();
|
||||
|
||||
void NotifyShutdown();
|
||||
|
||||
private:
|
||||
void SignalDequeueCondition();
|
||||
bool WaitForDequeueCondition(std::unique_lock<std::mutex>& lk);
|
||||
@@ -74,7 +72,6 @@ private:
|
||||
u32 transform_hint{};
|
||||
bool is_allocating{};
|
||||
mutable std::condition_variable_any is_allocating_condition;
|
||||
bool is_shutting_down{};
|
||||
};
|
||||
|
||||
} // namespace Service::android
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/service/hle_ipc.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/nvdrv/core/nvmap.h"
|
||||
#include "core/hle/service/nvnflinger/buffer_queue_core.h"
|
||||
#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
|
||||
#include "core/hle/service/nvnflinger/consumer_listener.h"
|
||||
@@ -533,8 +532,6 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
|
||||
item.is_droppable = core->dequeue_buffer_cannot_block || async;
|
||||
item.swap_interval = swap_interval;
|
||||
|
||||
nvmap.DuplicateHandle(item.graphic_buffer->BufferId(), true);
|
||||
|
||||
sticky_transform = sticky_transform_;
|
||||
|
||||
if (core->queue.empty()) {
|
||||
@@ -744,19 +741,13 @@ Status BufferQueueProducer::Disconnect(NativeWindowApi api) {
|
||||
return Status::NoError;
|
||||
}
|
||||
|
||||
// HACK: We are not Android. Remove handle for items in queue, and clear queue.
|
||||
// Allows synchronous destruction of nvmap handles.
|
||||
for (auto& item : core->queue) {
|
||||
nvmap.FreeHandle(item.graphic_buffer->BufferId(), true);
|
||||
}
|
||||
core->queue.clear();
|
||||
|
||||
switch (api) {
|
||||
case NativeWindowApi::Egl:
|
||||
case NativeWindowApi::Cpu:
|
||||
case NativeWindowApi::Media:
|
||||
case NativeWindowApi::Camera:
|
||||
if (core->connected_api == api) {
|
||||
core->queue.clear();
|
||||
core->FreeAllBuffersLocked();
|
||||
core->connected_producer_listener = nullptr;
|
||||
core->connected_api = NativeWindowApi::NoConnectedApi;
|
||||
@@ -785,7 +776,7 @@ Status BufferQueueProducer::Disconnect(NativeWindowApi api) {
|
||||
}
|
||||
|
||||
Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot,
|
||||
const std::shared_ptr<GraphicBuffer>& buffer) {
|
||||
const std::shared_ptr<NvGraphicBuffer>& buffer) {
|
||||
LOG_DEBUG(Service_Nvnflinger, "slot {}", slot);
|
||||
|
||||
if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
|
||||
@@ -796,7 +787,7 @@ Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot,
|
||||
|
||||
slots[slot] = {};
|
||||
slots[slot].fence = Fence::NoFence();
|
||||
slots[slot].graphic_buffer = buffer;
|
||||
slots[slot].graphic_buffer = std::make_shared<GraphicBuffer>(nvmap, buffer);
|
||||
slots[slot].frame_number = 0;
|
||||
|
||||
// Most games preallocate a buffer and pass a valid buffer here. However, it is possible for
|
||||
@@ -839,7 +830,7 @@ void BufferQueueProducer::Transact(HLERequestContext& ctx, TransactionId code, u
|
||||
}
|
||||
case TransactionId::SetPreallocatedBuffer: {
|
||||
const auto slot = parcel_in.Read<s32>();
|
||||
const auto buffer = parcel_in.ReadObject<GraphicBuffer>();
|
||||
const auto buffer = parcel_in.ReadObject<NvGraphicBuffer>();
|
||||
|
||||
status = SetPreallocatedBuffer(slot, buffer);
|
||||
break;
|
||||
@@ -867,7 +858,7 @@ void BufferQueueProducer::Transact(HLERequestContext& ctx, TransactionId code, u
|
||||
|
||||
status = RequestBuffer(slot, &buf);
|
||||
|
||||
parcel_out.WriteFlattenedObject(buf);
|
||||
parcel_out.WriteFlattenedObject<NvGraphicBuffer>(buf.get());
|
||||
break;
|
||||
}
|
||||
case TransactionId::QueueBuffer: {
|
||||
|
||||
@@ -38,6 +38,7 @@ namespace Service::android {
|
||||
|
||||
class BufferQueueCore;
|
||||
class IProducerListener;
|
||||
struct NvGraphicBuffer;
|
||||
|
||||
class BufferQueueProducer final : public IBinder {
|
||||
public:
|
||||
@@ -65,7 +66,7 @@ public:
|
||||
bool producer_controlled_by_app, QueueBufferOutput* output);
|
||||
|
||||
Status Disconnect(NativeWindowApi api);
|
||||
Status SetPreallocatedBuffer(s32 slot, const std::shared_ptr<GraphicBuffer>& buffer);
|
||||
Status SetPreallocatedBuffer(s32 slot, const std::shared_ptr<NvGraphicBuffer>& buffer);
|
||||
|
||||
private:
|
||||
BufferQueueProducer(const BufferQueueProducer&) = delete;
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
namespace Service::android {
|
||||
|
||||
struct GraphicBuffer;
|
||||
class GraphicBuffer;
|
||||
|
||||
enum class BufferState : u32 {
|
||||
Free = 0,
|
||||
|
||||
@@ -27,6 +27,26 @@ void ConsumerBase::Connect(bool controlled_by_app) {
|
||||
consumer->Connect(shared_from_this(), controlled_by_app);
|
||||
}
|
||||
|
||||
void ConsumerBase::Abandon() {
|
||||
LOG_DEBUG(Service_Nvnflinger, "called");
|
||||
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
if (!is_abandoned) {
|
||||
this->AbandonLocked();
|
||||
is_abandoned = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ConsumerBase::AbandonLocked() {
|
||||
for (int i = 0; i < BufferQueueDefs::NUM_BUFFER_SLOTS; i++) {
|
||||
this->FreeBufferLocked(i);
|
||||
}
|
||||
// disconnect from the BufferQueue
|
||||
consumer->Disconnect();
|
||||
consumer = nullptr;
|
||||
}
|
||||
|
||||
void ConsumerBase::FreeBufferLocked(s32 slot_index) {
|
||||
LOG_DEBUG(Service_Nvnflinger, "slot_index={}", slot_index);
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ class BufferQueueConsumer;
|
||||
class ConsumerBase : public IConsumerListener, public std::enable_shared_from_this<ConsumerBase> {
|
||||
public:
|
||||
void Connect(bool controlled_by_app);
|
||||
void Abandon();
|
||||
|
||||
protected:
|
||||
explicit ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_);
|
||||
@@ -34,6 +35,7 @@ protected:
|
||||
void OnBuffersReleased() override;
|
||||
void OnSidebandStreamChanged() override;
|
||||
|
||||
void AbandonLocked();
|
||||
void FreeBufferLocked(s32 slot_index);
|
||||
Status AcquireBufferLocked(BufferItem* item, std::chrono::nanoseconds present_when);
|
||||
Status ReleaseBufferLocked(s32 slot, const std::shared_ptr<GraphicBuffer>& graphic_buffer);
|
||||
|
||||
@@ -166,7 +166,7 @@ constexpr SharedMemoryPoolLayout SharedBufferPoolLayout = [] {
|
||||
}();
|
||||
|
||||
void MakeGraphicBuffer(android::BufferQueueProducer& producer, u32 slot, u32 handle) {
|
||||
auto buffer = std::make_shared<android::GraphicBuffer>();
|
||||
auto buffer = std::make_shared<android::NvGraphicBuffer>();
|
||||
buffer->width = SharedBufferWidth;
|
||||
buffer->height = SharedBufferHeight;
|
||||
buffer->stride = SharedBufferBlockLinearStride;
|
||||
|
||||
@@ -47,7 +47,10 @@ void Nvnflinger::SplitVSync(std::stop_token stop_token) {
|
||||
vsync_signal.Wait();
|
||||
|
||||
const auto lock_guard = Lock();
|
||||
Compose();
|
||||
|
||||
if (!is_abandoned) {
|
||||
Compose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +101,6 @@ Nvnflinger::~Nvnflinger() {
|
||||
}
|
||||
|
||||
ShutdownLayers();
|
||||
vsync_thread = {};
|
||||
|
||||
if (nvdrv) {
|
||||
nvdrv->Close(disp_fd);
|
||||
@@ -106,12 +108,20 @@ Nvnflinger::~Nvnflinger() {
|
||||
}
|
||||
|
||||
void Nvnflinger::ShutdownLayers() {
|
||||
const auto lock_guard = Lock();
|
||||
for (auto& display : displays) {
|
||||
for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) {
|
||||
display.GetLayer(layer).Core().NotifyShutdown();
|
||||
// Abandon consumers.
|
||||
{
|
||||
const auto lock_guard = Lock();
|
||||
for (auto& display : displays) {
|
||||
for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) {
|
||||
display.GetLayer(layer).GetConsumer().Abandon();
|
||||
}
|
||||
}
|
||||
|
||||
is_abandoned = true;
|
||||
}
|
||||
|
||||
// Join the vsync thread, if it exists.
|
||||
vsync_thread = {};
|
||||
}
|
||||
|
||||
void Nvnflinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
|
||||
|
||||
@@ -140,6 +140,8 @@ private:
|
||||
|
||||
s32 swap_interval = 1;
|
||||
|
||||
bool is_abandoned = false;
|
||||
|
||||
/// Event that handles screen composition.
|
||||
std::shared_ptr<Core::Timing::EventType> multi_composition_event;
|
||||
std::shared_ptr<Core::Timing::EventType> single_composition_event;
|
||||
|
||||
@@ -19,7 +19,7 @@ enum class Status : s32 {
|
||||
Busy = -16,
|
||||
NoInit = -19,
|
||||
BadValue = -22,
|
||||
InvalidOperation = -37,
|
||||
InvalidOperation = -38,
|
||||
BufferNeedsReallocation = 1,
|
||||
ReleaseAllBuffers = 2,
|
||||
};
|
||||
|
||||
34
src/core/hle/service/nvnflinger/ui/graphic_buffer.cpp
Normal file
34
src/core/hle/service/nvnflinger/ui/graphic_buffer.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "core/hle/service/nvdrv/core/nvmap.h"
|
||||
#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
|
||||
|
||||
namespace Service::android {
|
||||
|
||||
static NvGraphicBuffer GetBuffer(std::shared_ptr<NvGraphicBuffer>& buffer) {
|
||||
if (buffer) {
|
||||
return *buffer;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
GraphicBuffer::GraphicBuffer(u32 width_, u32 height_, PixelFormat format_, u32 usage_)
|
||||
: NvGraphicBuffer(width_, height_, format_, usage_), m_nvmap(nullptr) {}
|
||||
|
||||
GraphicBuffer::GraphicBuffer(Service::Nvidia::NvCore::NvMap& nvmap,
|
||||
std::shared_ptr<NvGraphicBuffer> buffer)
|
||||
: NvGraphicBuffer(GetBuffer(buffer)), m_nvmap(std::addressof(nvmap)) {
|
||||
if (this->BufferId() > 0) {
|
||||
m_nvmap->DuplicateHandle(this->BufferId(), true);
|
||||
}
|
||||
}
|
||||
|
||||
GraphicBuffer::~GraphicBuffer() {
|
||||
if (m_nvmap != nullptr && this->BufferId() > 0) {
|
||||
m_nvmap->FreeHandle(this->BufferId(), true);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Service::android
|
||||
@@ -6,16 +6,22 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/service/nvnflinger/pixel_format.h"
|
||||
|
||||
namespace Service::Nvidia::NvCore {
|
||||
class NvMap;
|
||||
} // namespace Service::Nvidia::NvCore
|
||||
|
||||
namespace Service::android {
|
||||
|
||||
struct GraphicBuffer final {
|
||||
constexpr GraphicBuffer() = default;
|
||||
struct NvGraphicBuffer {
|
||||
constexpr NvGraphicBuffer() = default;
|
||||
|
||||
constexpr GraphicBuffer(u32 width_, u32 height_, PixelFormat format_, u32 usage_)
|
||||
constexpr NvGraphicBuffer(u32 width_, u32 height_, PixelFormat format_, u32 usage_)
|
||||
: width{static_cast<s32>(width_)}, height{static_cast<s32>(height_)}, format{format_},
|
||||
usage{static_cast<s32>(usage_)} {}
|
||||
|
||||
@@ -93,6 +99,17 @@ struct GraphicBuffer final {
|
||||
u32 offset{};
|
||||
INSERT_PADDING_WORDS(60);
|
||||
};
|
||||
static_assert(sizeof(GraphicBuffer) == 0x16C, "GraphicBuffer has wrong size");
|
||||
static_assert(sizeof(NvGraphicBuffer) == 0x16C, "NvGraphicBuffer has wrong size");
|
||||
|
||||
class GraphicBuffer final : public NvGraphicBuffer {
|
||||
public:
|
||||
explicit GraphicBuffer(u32 width, u32 height, PixelFormat format, u32 usage);
|
||||
explicit GraphicBuffer(Service::Nvidia::NvCore::NvMap& nvmap,
|
||||
std::shared_ptr<NvGraphicBuffer> buffer);
|
||||
~GraphicBuffer();
|
||||
|
||||
private:
|
||||
Service::Nvidia::NvCore::NvMap* m_nvmap{};
|
||||
};
|
||||
|
||||
} // namespace Service::android
|
||||
|
||||
@@ -35,7 +35,7 @@ static BufferQueue CreateBufferQueue(KernelHelpers::ServiceContext& service_cont
|
||||
return {
|
||||
buffer_queue_core,
|
||||
std::make_unique<android::BufferQueueProducer>(service_context, buffer_queue_core, nvmap),
|
||||
std::make_unique<android::BufferQueueConsumer>(buffer_queue_core, nvmap)};
|
||||
std::make_unique<android::BufferQueueConsumer>(buffer_queue_core)};
|
||||
}
|
||||
|
||||
Display::Display(u64 id, std::string name_,
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// SPDX-FileCopyrightText: 2015 Citra Emulator Project
|
||||
// SPDX-FileCopyrightText: 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
#include <span>
|
||||
|
||||
#include "common/assert.h"
|
||||
@@ -10,6 +12,7 @@
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/page_table.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "common/settings.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/core.h"
|
||||
@@ -318,7 +321,7 @@ struct Memory::Impl {
|
||||
[&](const Common::ProcessAddress current_vaddr, const std::size_t copy_amount,
|
||||
u8* const host_ptr) {
|
||||
if constexpr (!UNSAFE) {
|
||||
system.GPU().InvalidateRegion(GetInteger(current_vaddr), copy_amount);
|
||||
HandleRasterizerWrite(GetInteger(current_vaddr), copy_amount);
|
||||
}
|
||||
std::memcpy(host_ptr, src_buffer, copy_amount);
|
||||
},
|
||||
@@ -351,7 +354,7 @@ struct Memory::Impl {
|
||||
},
|
||||
[&](const Common::ProcessAddress current_vaddr, const std::size_t copy_amount,
|
||||
u8* const host_ptr) {
|
||||
system.GPU().InvalidateRegion(GetInteger(current_vaddr), copy_amount);
|
||||
HandleRasterizerWrite(GetInteger(current_vaddr), copy_amount);
|
||||
std::memset(host_ptr, 0, copy_amount);
|
||||
},
|
||||
[](const std::size_t copy_amount) {});
|
||||
@@ -420,7 +423,7 @@ struct Memory::Impl {
|
||||
const std::size_t block_size) {
|
||||
// dc cvac: Store to point of coherency
|
||||
// CPU flush -> GPU invalidate
|
||||
system.GPU().InvalidateRegion(GetInteger(current_vaddr), block_size);
|
||||
HandleRasterizerWrite(GetInteger(current_vaddr), block_size);
|
||||
};
|
||||
return PerformCacheOperation(dest_addr, size, on_rasterizer);
|
||||
}
|
||||
@@ -430,7 +433,7 @@ struct Memory::Impl {
|
||||
const std::size_t block_size) {
|
||||
// dc civac: Store to point of coherency, and invalidate from cache
|
||||
// CPU flush -> GPU invalidate
|
||||
system.GPU().InvalidateRegion(GetInteger(current_vaddr), block_size);
|
||||
HandleRasterizerWrite(GetInteger(current_vaddr), block_size);
|
||||
};
|
||||
return PerformCacheOperation(dest_addr, size, on_rasterizer);
|
||||
}
|
||||
@@ -767,7 +770,18 @@ struct Memory::Impl {
|
||||
}
|
||||
|
||||
void HandleRasterizerWrite(VAddr address, size_t size) {
|
||||
const size_t core = system.GetCurrentHostThreadID();
|
||||
constexpr size_t sys_core = Core::Hardware::NUM_CPU_CORES - 1;
|
||||
const size_t core = std::min(system.GetCurrentHostThreadID(),
|
||||
sys_core); // any other calls threads go to syscore.
|
||||
// Guard on sys_core;
|
||||
if (core == sys_core) [[unlikely]] {
|
||||
sys_core_guard.lock();
|
||||
}
|
||||
SCOPE_EXIT({
|
||||
if (core == sys_core) [[unlikely]] {
|
||||
sys_core_guard.unlock();
|
||||
}
|
||||
});
|
||||
auto& current_area = rasterizer_write_areas[core];
|
||||
VAddr subaddress = address >> YUZU_PAGEBITS;
|
||||
bool do_collection = current_area.last_address == subaddress;
|
||||
@@ -799,6 +813,7 @@ struct Memory::Impl {
|
||||
rasterizer_read_areas{};
|
||||
std::array<GPUDirtyState, Core::Hardware::NUM_CPU_CORES> rasterizer_write_areas{};
|
||||
std::span<Core::GPUDirtyMemoryManager> gpu_dirty_managers;
|
||||
std::mutex sys_core_guard;
|
||||
};
|
||||
|
||||
Memory::Memory(Core::System& system_) : system{system_} {
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
#include "core/hle/kernel/k_page_table.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/service/hid/controllers/npad.h"
|
||||
#include "core/hle/service/hid/hid.h"
|
||||
#include "core/hle/service/hid/hid_server.h"
|
||||
#include "core/hle/service/hid/resource_manager.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/memory/cheat_engine.h"
|
||||
@@ -54,13 +55,13 @@ void StandardVmCallbacks::MemoryWrite(VAddr address, const void* data, u64 size)
|
||||
}
|
||||
|
||||
u64 StandardVmCallbacks::HidKeysDown() {
|
||||
const auto hid = system.ServiceManager().GetService<Service::HID::Hid>("hid");
|
||||
const auto hid = system.ServiceManager().GetService<Service::HID::IHidServer>("hid");
|
||||
if (hid == nullptr) {
|
||||
LOG_WARNING(CheatEngine, "Attempted to read input state, but hid is not initialized!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto applet_resource = hid->GetAppletResource();
|
||||
const auto applet_resource = hid->GetResourceManager();
|
||||
if (applet_resource == nullptr) {
|
||||
LOG_WARNING(CheatEngine,
|
||||
"Attempted to read input state, but applet resource is not initialized!");
|
||||
|
||||
@@ -231,6 +231,7 @@ add_library(shader_recompiler STATIC
|
||||
ir_opt/rescaling_pass.cpp
|
||||
ir_opt/ssa_rewrite_pass.cpp
|
||||
ir_opt/texture_pass.cpp
|
||||
ir_opt/vendor_workaround_pass.cpp
|
||||
ir_opt/verification_pass.cpp
|
||||
object_pool.h
|
||||
precompiled_headers.h
|
||||
|
||||
@@ -559,12 +559,12 @@ void EmitImageGradient(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
|
||||
const IR::Value& offset, const IR::Value& lod_clamp) {
|
||||
const auto info{inst.Flags<IR::TextureInstInfo>()};
|
||||
ScopedRegister dpdx, dpdy, coords;
|
||||
const bool multi_component{info.num_derivates > 1 || info.has_lod_clamp};
|
||||
const bool multi_component{info.num_derivatives > 1 || info.has_lod_clamp};
|
||||
if (multi_component) {
|
||||
// Allocate this early to avoid aliasing other registers
|
||||
dpdx = ScopedRegister{ctx.reg_alloc};
|
||||
dpdy = ScopedRegister{ctx.reg_alloc};
|
||||
if (info.num_derivates >= 3) {
|
||||
if (info.num_derivatives >= 3) {
|
||||
coords = ScopedRegister{ctx.reg_alloc};
|
||||
}
|
||||
}
|
||||
@@ -584,7 +584,7 @@ void EmitImageGradient(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
|
||||
dpdx.reg, derivatives_vec, dpdx.reg, derivatives_vec, dpdy.reg, derivatives_vec,
|
||||
dpdy.reg, derivatives_vec);
|
||||
Register final_coord;
|
||||
if (info.num_derivates >= 3) {
|
||||
if (info.num_derivatives >= 3) {
|
||||
ctx.Add("MOV.F {}.z,{}.x;"
|
||||
"MOV.F {}.z,{}.y;",
|
||||
dpdx.reg, coord_vec, dpdy.reg, coord_vec);
|
||||
|
||||
@@ -548,15 +548,15 @@ void EmitImageGradient(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
|
||||
if (sparse_inst) {
|
||||
throw NotImplementedException("EmitImageGradient Sparse");
|
||||
}
|
||||
if (!offset.IsEmpty() && info.num_derivates <= 2) {
|
||||
if (!offset.IsEmpty() && info.num_derivatives <= 2) {
|
||||
throw NotImplementedException("EmitImageGradient offset");
|
||||
}
|
||||
const auto texture{Texture(ctx, info, index)};
|
||||
const auto texel{ctx.var_alloc.Define(inst, GlslVarType::F32x4)};
|
||||
const bool multi_component{info.num_derivates > 1 || info.has_lod_clamp};
|
||||
const bool multi_component{info.num_derivatives > 1 || info.has_lod_clamp};
|
||||
const auto derivatives_vec{ctx.var_alloc.Consume(derivatives)};
|
||||
if (multi_component) {
|
||||
if (info.num_derivates >= 3) {
|
||||
if (info.num_derivatives >= 3) {
|
||||
const auto offset_vec{ctx.var_alloc.Consume(offset)};
|
||||
ctx.Add("{}=textureGrad({},{},vec3({}.xz, {}.x),vec3({}.yw, {}.y));", texel, texture,
|
||||
coords, derivatives_vec, offset_vec, derivatives_vec, offset_vec);
|
||||
|
||||
@@ -407,7 +407,7 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct
|
||||
}
|
||||
ctx.AddCapability(spv::Capability::DemoteToHelperInvocation);
|
||||
}
|
||||
if (info.stores[IR::Attribute::ViewportIndex]) {
|
||||
if (info.stores[IR::Attribute::ViewportIndex] && profile.support_multi_viewport) {
|
||||
ctx.AddCapability(spv::Capability::MultiViewport);
|
||||
}
|
||||
if (info.stores[IR::Attribute::ViewportMask] && profile.support_viewport_mask) {
|
||||
|
||||
@@ -84,6 +84,10 @@ std::optional<OutAttr> OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) {
|
||||
}
|
||||
return std::nullopt;
|
||||
case IR::Attribute::ViewportIndex:
|
||||
if (!ctx.profile.support_multi_viewport) {
|
||||
LOG_WARNING(Shader, "Ignoring viewport index store on non-supporting driver");
|
||||
return std::nullopt;
|
||||
}
|
||||
if (ctx.profile.support_viewport_index_layer_non_geometry ||
|
||||
ctx.stage == Shader::Stage::Geometry) {
|
||||
return OutAttr{ctx.viewport_index, ctx.U32[1]};
|
||||
|
||||
@@ -67,22 +67,22 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivates, u32 num_derivates,
|
||||
Id offset, Id lod_clamp) {
|
||||
if (!Sirit::ValidId(derivates)) {
|
||||
throw LogicError("Derivates must be present");
|
||||
explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivatives,
|
||||
u32 num_derivatives, Id offset, Id lod_clamp) {
|
||||
if (!Sirit::ValidId(derivatives)) {
|
||||
throw LogicError("Derivatives must be present");
|
||||
}
|
||||
boost::container::static_vector<Id, 3> deriv_x_accum;
|
||||
boost::container::static_vector<Id, 3> deriv_y_accum;
|
||||
for (u32 i = 0; i < num_derivates; ++i) {
|
||||
deriv_x_accum.push_back(ctx.OpCompositeExtract(ctx.F32[1], derivates, i * 2));
|
||||
deriv_y_accum.push_back(ctx.OpCompositeExtract(ctx.F32[1], derivates, i * 2 + 1));
|
||||
for (u32 i = 0; i < num_derivatives; ++i) {
|
||||
deriv_x_accum.push_back(ctx.OpCompositeExtract(ctx.F32[1], derivatives, i * 2));
|
||||
deriv_y_accum.push_back(ctx.OpCompositeExtract(ctx.F32[1], derivatives, i * 2 + 1));
|
||||
}
|
||||
const Id derivates_X{ctx.OpCompositeConstruct(
|
||||
ctx.F32[num_derivates], std::span{deriv_x_accum.data(), deriv_x_accum.size()})};
|
||||
const Id derivates_Y{ctx.OpCompositeConstruct(
|
||||
ctx.F32[num_derivates], std::span{deriv_y_accum.data(), deriv_y_accum.size()})};
|
||||
Add(spv::ImageOperandsMask::Grad, derivates_X, derivates_Y);
|
||||
const Id derivatives_X{ctx.OpCompositeConstruct(
|
||||
ctx.F32[num_derivatives], std::span{deriv_x_accum.data(), deriv_x_accum.size()})};
|
||||
const Id derivatives_Y{ctx.OpCompositeConstruct(
|
||||
ctx.F32[num_derivatives], std::span{deriv_y_accum.data(), deriv_y_accum.size()})};
|
||||
Add(spv::ImageOperandsMask::Grad, derivatives_X, derivatives_Y);
|
||||
if (Sirit::ValidId(offset)) {
|
||||
Add(spv::ImageOperandsMask::Offset, offset);
|
||||
}
|
||||
@@ -91,26 +91,26 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivates_1, Id derivates_2,
|
||||
explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivatives_1, Id derivatives_2,
|
||||
Id offset, Id lod_clamp) {
|
||||
if (!Sirit::ValidId(derivates_1) || !Sirit::ValidId(derivates_2)) {
|
||||
throw LogicError("Derivates must be present");
|
||||
if (!Sirit::ValidId(derivatives_1) || !Sirit::ValidId(derivatives_2)) {
|
||||
throw LogicError("Derivatives must be present");
|
||||
}
|
||||
boost::container::static_vector<Id, 3> deriv_1_accum{
|
||||
ctx.OpCompositeExtract(ctx.F32[1], derivates_1, 0),
|
||||
ctx.OpCompositeExtract(ctx.F32[1], derivates_1, 2),
|
||||
ctx.OpCompositeExtract(ctx.F32[1], derivates_2, 0),
|
||||
ctx.OpCompositeExtract(ctx.F32[1], derivatives_1, 0),
|
||||
ctx.OpCompositeExtract(ctx.F32[1], derivatives_1, 2),
|
||||
ctx.OpCompositeExtract(ctx.F32[1], derivatives_2, 0),
|
||||
};
|
||||
boost::container::static_vector<Id, 3> deriv_2_accum{
|
||||
ctx.OpCompositeExtract(ctx.F32[1], derivates_1, 1),
|
||||
ctx.OpCompositeExtract(ctx.F32[1], derivates_1, 3),
|
||||
ctx.OpCompositeExtract(ctx.F32[1], derivates_2, 1),
|
||||
ctx.OpCompositeExtract(ctx.F32[1], derivatives_1, 1),
|
||||
ctx.OpCompositeExtract(ctx.F32[1], derivatives_1, 3),
|
||||
ctx.OpCompositeExtract(ctx.F32[1], derivatives_2, 1),
|
||||
};
|
||||
const Id derivates_id1{ctx.OpCompositeConstruct(
|
||||
const Id derivatives_id1{ctx.OpCompositeConstruct(
|
||||
ctx.F32[3], std::span{deriv_1_accum.data(), deriv_1_accum.size()})};
|
||||
const Id derivates_id2{ctx.OpCompositeConstruct(
|
||||
const Id derivatives_id2{ctx.OpCompositeConstruct(
|
||||
ctx.F32[3], std::span{deriv_2_accum.data(), deriv_2_accum.size()})};
|
||||
Add(spv::ImageOperandsMask::Grad, derivates_id1, derivates_id2);
|
||||
Add(spv::ImageOperandsMask::Grad, derivatives_id1, derivatives_id2);
|
||||
if (Sirit::ValidId(offset)) {
|
||||
Add(spv::ImageOperandsMask::Offset, offset);
|
||||
}
|
||||
@@ -548,12 +548,12 @@ Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, I
|
||||
}
|
||||
|
||||
Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
||||
Id derivates, Id offset, Id lod_clamp) {
|
||||
Id derivatives, Id offset, Id lod_clamp) {
|
||||
const auto info{inst->Flags<IR::TextureInstInfo>()};
|
||||
const auto operands =
|
||||
info.num_derivates == 3
|
||||
? ImageOperands(ctx, info.has_lod_clamp != 0, derivates, offset, {}, lod_clamp)
|
||||
: ImageOperands(ctx, info.has_lod_clamp != 0, derivates, info.num_derivates, offset,
|
||||
info.num_derivatives == 3
|
||||
? ImageOperands(ctx, info.has_lod_clamp != 0, derivatives, offset, {}, lod_clamp)
|
||||
: ImageOperands(ctx, info.has_lod_clamp != 0, derivatives, info.num_derivatives, offset,
|
||||
lod_clamp);
|
||||
return Emit(&EmitContext::OpImageSparseSampleExplicitLod,
|
||||
&EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4],
|
||||
|
||||
@@ -543,7 +543,7 @@ Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& i
|
||||
const IR::Value& skip_mips);
|
||||
Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords);
|
||||
Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
||||
Id derivates, Id offset, Id lod_clamp);
|
||||
Id derivatives, Id offset, Id lod_clamp);
|
||||
Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords);
|
||||
void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color);
|
||||
Id EmitIsTextureScaled(EmitContext& ctx, const IR::Value& index);
|
||||
|
||||
@@ -1864,11 +1864,11 @@ Value IREmitter::ImageQueryLod(const Value& handle, const Value& coords, Texture
|
||||
return Inst(op, Flags{info}, handle, coords);
|
||||
}
|
||||
|
||||
Value IREmitter::ImageGradient(const Value& handle, const Value& coords, const Value& derivates,
|
||||
Value IREmitter::ImageGradient(const Value& handle, const Value& coords, const Value& derivatives,
|
||||
const Value& offset, const F32& lod_clamp, TextureInstInfo info) {
|
||||
const Opcode op{handle.IsImmediate() ? Opcode::BoundImageGradient
|
||||
: Opcode::BindlessImageGradient};
|
||||
return Inst(op, Flags{info}, handle, coords, derivates, offset, lod_clamp);
|
||||
return Inst(op, Flags{info}, handle, coords, derivatives, offset, lod_clamp);
|
||||
}
|
||||
|
||||
Value IREmitter::ImageRead(const Value& handle, const Value& coords, TextureInstInfo info) {
|
||||
|
||||
@@ -335,7 +335,7 @@ public:
|
||||
[[nodiscard]] Value ImageFetch(const Value& handle, const Value& coords, const Value& offset,
|
||||
const U32& lod, const U32& multisampling, TextureInstInfo info);
|
||||
[[nodiscard]] Value ImageGradient(const Value& handle, const Value& coords,
|
||||
const Value& derivates, const Value& offset,
|
||||
const Value& derivatives, const Value& offset,
|
||||
const F32& lod_clamp, TextureInstInfo info);
|
||||
[[nodiscard]] Value ImageRead(const Value& handle, const Value& coords, TextureInstInfo info);
|
||||
void ImageWrite(const Value& handle, const Value& coords, const Value& color,
|
||||
|
||||
@@ -40,7 +40,7 @@ union TextureInstInfo {
|
||||
BitField<21, 1, u32> has_lod_clamp;
|
||||
BitField<22, 1, u32> relaxed_precision;
|
||||
BitField<23, 2, u32> gather_component;
|
||||
BitField<25, 2, u32> num_derivates;
|
||||
BitField<25, 2, u32> num_derivatives;
|
||||
BitField<27, 3, ImageFormat> image_format;
|
||||
BitField<30, 1, u32> ndv_is_active;
|
||||
};
|
||||
|
||||
@@ -59,7 +59,7 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
||||
BitField<51, 3, IR::Pred> sparse_pred;
|
||||
BitField<0, 8, IR::Reg> dest_reg;
|
||||
BitField<8, 8, IR::Reg> coord_reg;
|
||||
BitField<20, 8, IR::Reg> derivate_reg;
|
||||
BitField<20, 8, IR::Reg> derivative_reg;
|
||||
BitField<28, 3, TextureType> type;
|
||||
BitField<31, 4, u64> mask;
|
||||
BitField<36, 13, u64> cbuf_offset;
|
||||
@@ -71,7 +71,7 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
||||
}
|
||||
|
||||
IR::Value coords;
|
||||
u32 num_derivates{};
|
||||
u32 num_derivatives{};
|
||||
IR::Reg base_reg{txd.coord_reg};
|
||||
IR::Reg last_reg;
|
||||
IR::Value handle;
|
||||
@@ -90,42 +90,42 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
||||
switch (txd.type) {
|
||||
case TextureType::_1D: {
|
||||
coords = v.F(base_reg);
|
||||
num_derivates = 1;
|
||||
num_derivatives = 1;
|
||||
last_reg = base_reg + 1;
|
||||
break;
|
||||
}
|
||||
case TextureType::ARRAY_1D: {
|
||||
last_reg = base_reg + 1;
|
||||
coords = v.ir.CompositeConstruct(v.F(base_reg), read_array());
|
||||
num_derivates = 1;
|
||||
num_derivatives = 1;
|
||||
break;
|
||||
}
|
||||
case TextureType::_2D: {
|
||||
last_reg = base_reg + 2;
|
||||
coords = v.ir.CompositeConstruct(v.F(base_reg), v.F(base_reg + 1));
|
||||
num_derivates = 2;
|
||||
num_derivatives = 2;
|
||||
break;
|
||||
}
|
||||
case TextureType::ARRAY_2D: {
|
||||
last_reg = base_reg + 2;
|
||||
coords = v.ir.CompositeConstruct(v.F(base_reg), v.F(base_reg + 1), read_array());
|
||||
num_derivates = 2;
|
||||
num_derivatives = 2;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw NotImplementedException("Invalid texture type");
|
||||
}
|
||||
|
||||
const IR::Reg derivate_reg{txd.derivate_reg};
|
||||
IR::Value derivates;
|
||||
switch (num_derivates) {
|
||||
const IR::Reg derivative_reg{txd.derivative_reg};
|
||||
IR::Value derivatives;
|
||||
switch (num_derivatives) {
|
||||
case 1: {
|
||||
derivates = v.ir.CompositeConstruct(v.F(derivate_reg), v.F(derivate_reg + 1));
|
||||
derivatives = v.ir.CompositeConstruct(v.F(derivative_reg), v.F(derivative_reg + 1));
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
derivates = v.ir.CompositeConstruct(v.F(derivate_reg), v.F(derivate_reg + 1),
|
||||
v.F(derivate_reg + 2), v.F(derivate_reg + 3));
|
||||
derivatives = v.ir.CompositeConstruct(v.F(derivative_reg), v.F(derivative_reg + 1),
|
||||
v.F(derivative_reg + 2), v.F(derivative_reg + 3));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -150,9 +150,10 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
||||
|
||||
IR::TextureInstInfo info{};
|
||||
info.type.Assign(GetType(txd.type));
|
||||
info.num_derivates.Assign(num_derivates);
|
||||
info.num_derivatives.Assign(num_derivatives);
|
||||
info.has_lod_clamp.Assign(has_lod_clamp ? 1 : 0);
|
||||
const IR::Value sample{v.ir.ImageGradient(handle, coords, derivates, offset, lod_clamp, info)};
|
||||
const IR::Value sample{
|
||||
v.ir.ImageGradient(handle, coords, derivatives, offset, lod_clamp, info)};
|
||||
|
||||
IR::Reg dest_reg{txd.dest_reg};
|
||||
for (size_t element = 0; element < 4; ++element) {
|
||||
|
||||
@@ -310,6 +310,7 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo
|
||||
}
|
||||
Optimization::CollectShaderInfoPass(env, program);
|
||||
Optimization::LayerPass(program, host_info);
|
||||
Optimization::VendorWorkaroundPass(program);
|
||||
|
||||
CollectInterpolationInfo(env, program);
|
||||
AddNVNStorageBuffers(program);
|
||||
|
||||
@@ -428,7 +428,7 @@ void FoldFPAdd32(IR::Inst& inst) {
|
||||
}
|
||||
}
|
||||
|
||||
bool FoldDerivateYFromCorrection(IR::Inst& inst) {
|
||||
bool FoldDerivativeYFromCorrection(IR::Inst& inst) {
|
||||
const IR::Value lhs_value{inst.Arg(0)};
|
||||
const IR::Value rhs_value{inst.Arg(1)};
|
||||
IR::Inst* const lhs_op{lhs_value.InstRecursive()};
|
||||
@@ -464,7 +464,7 @@ void FoldFPMul32(IR::Inst& inst) {
|
||||
if (lhs_value.IsImmediate() || rhs_value.IsImmediate()) {
|
||||
return;
|
||||
}
|
||||
if (FoldDerivateYFromCorrection(inst)) {
|
||||
if (FoldDerivativeYFromCorrection(inst)) {
|
||||
return;
|
||||
}
|
||||
IR::Inst* const lhs_op{lhs_value.InstRecursive()};
|
||||
@@ -699,7 +699,7 @@ void FoldFSwizzleAdd(IR::Block& block, IR::Inst& inst) {
|
||||
}
|
||||
}
|
||||
|
||||
bool FindGradient3DDerivates(std::array<IR::Value, 3>& results, IR::Value coord) {
|
||||
bool FindGradient3DDerivatives(std::array<IR::Value, 3>& results, IR::Value coord) {
|
||||
if (coord.IsImmediate()) {
|
||||
return false;
|
||||
}
|
||||
@@ -834,7 +834,7 @@ void FoldImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) {
|
||||
IR::Inst* const inst2 = coords.InstRecursive();
|
||||
std::array<std::array<IR::Value, 3>, 3> results_matrix;
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
if (!FindGradient3DDerivates(results_matrix[i], inst2->Arg(i).Resolve())) {
|
||||
if (!FindGradient3DDerivatives(results_matrix[i], inst2->Arg(i).Resolve())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -852,7 +852,7 @@ void FoldImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) {
|
||||
IR::Value derivatives_1 = ir.CompositeConstruct(results_matrix[0][1], results_matrix[0][2],
|
||||
results_matrix[1][1], results_matrix[1][2]);
|
||||
IR::Value derivatives_2 = ir.CompositeConstruct(results_matrix[2][1], results_matrix[2][2]);
|
||||
info.num_derivates.Assign(3);
|
||||
info.num_derivatives.Assign(3);
|
||||
IR::Value new_gradient_instruction =
|
||||
ir.ImageGradient(handle, new_coords, derivatives_1, derivatives_2, lod_clamp, info);
|
||||
IR::Inst* const new_inst = new_gradient_instruction.InstRecursive();
|
||||
|
||||
@@ -26,6 +26,7 @@ void SsaRewritePass(IR::Program& program);
|
||||
void PositionPass(Environment& env, IR::Program& program);
|
||||
void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo& host_info);
|
||||
void LayerPass(IR::Program& program, const HostTranslateInfo& host_info);
|
||||
void VendorWorkaroundPass(IR::Program& program);
|
||||
void VerificationPass(const IR::Program& program);
|
||||
|
||||
// Dual Vertex
|
||||
|
||||
79
src/shader_recompiler/ir_opt/vendor_workaround_pass.cpp
Normal file
79
src/shader_recompiler/ir_opt/vendor_workaround_pass.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "shader_recompiler/frontend/ir/basic_block.h"
|
||||
#include "shader_recompiler/frontend/ir/ir_emitter.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
#include "shader_recompiler/ir_opt/passes.h"
|
||||
|
||||
namespace Shader::Optimization {
|
||||
|
||||
namespace {
|
||||
void AddingByteSwapsWorkaround(IR::Block& block, IR::Inst& inst) {
|
||||
/*
|
||||
* Workaround for an NVIDIA bug seen in Super Mario RPG
|
||||
*
|
||||
* We are looking for this pattern:
|
||||
* %lhs_bfe = BitFieldUExtract %factor_a, #0, #16
|
||||
* %lhs_mul = IMul32 %lhs_bfe, %factor_b // potentially optional?
|
||||
* %lhs_shl = ShiftLeftLogical32 %lhs_mul, #16
|
||||
* %rhs_bfe = BitFieldUExtract %factor_a, #16, #16
|
||||
* %result = IAdd32 %lhs_shl, %rhs_bfe
|
||||
*
|
||||
* And replacing the IAdd32 with a BitwiseOr32
|
||||
* %result = BitwiseOr32 %lhs_shl, %rhs_bfe
|
||||
*
|
||||
*/
|
||||
IR::Inst* const lhs_shl{inst.Arg(0).TryInstRecursive()};
|
||||
IR::Inst* const rhs_bfe{inst.Arg(1).TryInstRecursive()};
|
||||
if (!lhs_shl || !rhs_bfe) {
|
||||
return;
|
||||
}
|
||||
if (lhs_shl->GetOpcode() != IR::Opcode::ShiftLeftLogical32 ||
|
||||
lhs_shl->Arg(1) != IR::Value{16U}) {
|
||||
return;
|
||||
}
|
||||
if (rhs_bfe->GetOpcode() != IR::Opcode::BitFieldUExtract || rhs_bfe->Arg(1) != IR::Value{16U} ||
|
||||
rhs_bfe->Arg(2) != IR::Value{16U}) {
|
||||
return;
|
||||
}
|
||||
IR::Inst* const lhs_mul{lhs_shl->Arg(0).TryInstRecursive()};
|
||||
if (!lhs_mul) {
|
||||
return;
|
||||
}
|
||||
const bool lhs_mul_optional{lhs_mul->GetOpcode() == IR::Opcode::BitFieldUExtract};
|
||||
if (lhs_mul->GetOpcode() != IR::Opcode::IMul32 &&
|
||||
lhs_mul->GetOpcode() != IR::Opcode::BitFieldUExtract) {
|
||||
return;
|
||||
}
|
||||
IR::Inst* const lhs_bfe{lhs_mul_optional ? lhs_mul : lhs_mul->Arg(0).TryInstRecursive()};
|
||||
if (!lhs_bfe) {
|
||||
return;
|
||||
}
|
||||
if (lhs_bfe->GetOpcode() != IR::Opcode::BitFieldUExtract) {
|
||||
return;
|
||||
}
|
||||
if (lhs_bfe->Arg(1) != IR::Value{0U} || lhs_bfe->Arg(2) != IR::Value{16U}) {
|
||||
return;
|
||||
}
|
||||
IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
|
||||
inst.ReplaceUsesWith(ir.BitwiseOr(IR::U32{inst.Arg(0)}, IR::U32{inst.Arg(1)}));
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
void VendorWorkaroundPass(IR::Program& program) {
|
||||
for (IR::Block* const block : program.post_order_blocks) {
|
||||
for (IR::Inst& inst : block->Instructions()) {
|
||||
switch (inst.GetOpcode()) {
|
||||
case IR::Opcode::IAdd32:
|
||||
AddingByteSwapsWorkaround(*block, inst);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Shader::Optimization
|
||||
@@ -43,6 +43,7 @@ struct Profile {
|
||||
bool support_gl_sparse_textures{};
|
||||
bool support_gl_derivative_control{};
|
||||
bool support_scaled_attributes{};
|
||||
bool support_multi_viewport{};
|
||||
|
||||
bool warp_size_potentially_larger_than_guest{};
|
||||
|
||||
|
||||
@@ -1192,11 +1192,6 @@ void BufferCache<P>::UpdateDrawIndirect() {
|
||||
.size = static_cast<u32>(size),
|
||||
.buffer_id = FindBuffer(*cpu_addr, static_cast<u32>(size)),
|
||||
};
|
||||
VAddr cpu_addr_start = Common::AlignDown(*cpu_addr, 64);
|
||||
VAddr cpu_addr_end = Common::AlignUp(*cpu_addr + size, 64);
|
||||
IntervalType interval{cpu_addr_start, cpu_addr_end};
|
||||
ClearDownload(interval);
|
||||
common_ranges.subtract(interval);
|
||||
};
|
||||
if (current_draw_indirect->include_count) {
|
||||
update(current_draw_indirect->count_start_address, sizeof(u32),
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user