diff options
62 files changed, 977 insertions, 458 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/PlayerInput.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/PlayerInput.kt index d35de80c4..a84ac77a2 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/PlayerInput.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/PlayerInput.kt @@ -64,17 +64,17 @@ data class PlayerInput( fun hasMapping(): Boolean { var hasMapping = false buttons.forEach { - if (it != "[empty]") { + if (it != "[empty]" && it.isNotEmpty()) { hasMapping = true } } analogs.forEach { - if (it != "[empty]") { + if (it != "[empty]" && it.isNotEmpty()) { hasMapping = true } } motions.forEach { - if (it != "[empty]") { + if (it != "[empty]" && it.isNotEmpty()) { hasMapping = true } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt index a0d8cfede..6f16cf5b1 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt @@ -6,7 +6,8 @@ package org.yuzu.yuzu_emu.features.settings.model import org.yuzu.yuzu_emu.utils.NativeConfig enum class StringSetting(override val key: String) : AbstractStringSetting { - DRIVER_PATH("driver_path"); + DRIVER_PATH("driver_path"), + DEVICE_NAME("device_name"); override fun getString(needsGlobal: Boolean): String = NativeConfig.getString(key, needsGlobal) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt index 8f724835e..5fdf98318 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt @@ -16,6 +16,7 @@ import org.yuzu.yuzu_emu.features.settings.model.ByteSetting import org.yuzu.yuzu_emu.features.settings.model.IntSetting import org.yuzu.yuzu_emu.features.settings.model.LongSetting import org.yuzu.yuzu_emu.features.settings.model.ShortSetting +import org.yuzu.yuzu_emu.features.settings.model.StringSetting import org.yuzu.yuzu_emu.utils.NativeConfig /** @@ -75,6 +76,9 @@ abstract class SettingsItem( get() = NativeLibrary.isRunning() && !setting.global && !NativeConfig.isPerGameConfigLoaded() + val clearable: Boolean + get() = !setting.global && NativeConfig.isPerGameConfigLoaded() + companion object { const val TYPE_HEADER = 0 const val TYPE_SWITCH = 1 @@ -87,6 +91,7 @@ abstract class SettingsItem( const val TYPE_INPUT = 8 const val TYPE_INT_SINGLE_CHOICE = 9 const val TYPE_INPUT_PROFILE = 10 + const val TYPE_STRING_INPUT = 11 const val FASTMEM_COMBINED = "fastmem_combined" @@ -105,6 +110,7 @@ abstract class SettingsItem( // List of all general val settingsItems = HashMap<String, SettingsItem>().apply { + put(StringInputSetting(StringSetting.DEVICE_NAME, titleId = R.string.device_name)) put( SwitchSetting( BooleanSetting.RENDERER_USE_SPEED_LIMIT, diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringInputSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringInputSetting.kt new file mode 100644 index 000000000..1eb999416 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringInputSetting.kt @@ -0,0 +1,22 @@ +// SPDX-FileCopyrightText: 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.yuzu.yuzu_emu.features.settings.model.view + +import androidx.annotation.StringRes +import org.yuzu.yuzu_emu.features.settings.model.AbstractStringSetting + +class StringInputSetting( + setting: AbstractStringSetting, + @StringRes titleId: Int = 0, + titleString: String = "", + @StringRes descriptionId: Int = 0, + descriptionString: String = "" +) : SettingsItem(setting, titleId, titleString, descriptionId, descriptionString) { + override val type = TYPE_STRING_INPUT + + fun getSelectedValue(needsGlobal: Boolean = false) = setting.getValueAsString(needsGlobal) + + fun setSelectedValue(selection: String) = + (setting as AbstractStringSetting).setString(selection) +} diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt index 45c8faa10..500ac6e66 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt @@ -85,6 +85,10 @@ class SettingsAdapter( InputProfileViewHolder(ListItemSettingBinding.inflate(inflater), this) } + SettingsItem.TYPE_STRING_INPUT -> { + StringInputViewHolder(ListItemSettingBinding.inflate(inflater), this) + } + else -> { HeaderViewHolder(ListItemSettingsHeaderBinding.inflate(inflater), this) } @@ -392,6 +396,15 @@ class SettingsAdapter( popup.show() } + fun onStringInputClick(item: StringInputSetting, position: Int) { + SettingsDialogFragment.newInstance( + settingsViewModel, + item, + SettingsItem.TYPE_STRING_INPUT, + position + ).show(fragment.childFragmentManager, SettingsDialogFragment.TAG) + } + fun onLongClick(item: SettingsItem, position: Int): Boolean { SettingsDialogFragment.newInstance( settingsViewModel, diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt index a81ff6b1a..7f562a1f4 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt @@ -14,6 +14,7 @@ import androidx.fragment.app.activityViewModels import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.slider.Slider import org.yuzu.yuzu_emu.R +import org.yuzu.yuzu_emu.databinding.DialogEditTextBinding import org.yuzu.yuzu_emu.databinding.DialogSliderBinding import org.yuzu.yuzu_emu.features.input.NativeInput import org.yuzu.yuzu_emu.features.input.model.AnalogDirection @@ -23,6 +24,7 @@ import org.yuzu.yuzu_emu.features.settings.model.view.IntSingleChoiceSetting import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting +import org.yuzu.yuzu_emu.features.settings.model.view.StringInputSetting import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting import org.yuzu.yuzu_emu.utils.ParamPackage import org.yuzu.yuzu_emu.utils.collect @@ -37,6 +39,7 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener private val settingsViewModel: SettingsViewModel by activityViewModels() private lateinit var sliderBinding: DialogSliderBinding + private lateinit var stringInputBinding: DialogEditTextBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -131,6 +134,18 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener .create() } + SettingsItem.TYPE_STRING_INPUT -> { + stringInputBinding = DialogEditTextBinding.inflate(layoutInflater) + val item = settingsViewModel.clickedItem as StringInputSetting + stringInputBinding.editText.setText(item.getSelectedValue()) + MaterialAlertDialogBuilder(requireContext()) + .setTitle(item.title) + .setView(stringInputBinding.root) + .setPositiveButton(android.R.string.ok, this) + .setNegativeButton(android.R.string.cancel, defaultCancelListener) + .create() + } + SettingsItem.TYPE_STRING_SINGLE_CHOICE -> { val item = settingsViewModel.clickedItem as StringSingleChoiceSetting MaterialAlertDialogBuilder(requireContext()) @@ -158,6 +173,7 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener ): View? { return when (type) { SettingsItem.TYPE_SLIDER -> sliderBinding.root + SettingsItem.TYPE_STRING_INPUT -> stringInputBinding.root else -> super.onCreateView(inflater, container, savedInstanceState) } } @@ -200,6 +216,13 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener val sliderSetting = settingsViewModel.clickedItem as SliderSetting sliderSetting.setSelectedValue(settingsViewModel.sliderProgress.value) } + + is StringInputSetting -> { + val stringInputSetting = settingsViewModel.clickedItem as StringInputSetting + stringInputSetting.setSelectedValue( + (stringInputBinding.editText.text ?: "").toString() + ) + } } closeDialog() } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt index e491c29a2..3ea5f5008 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -23,6 +23,7 @@ import org.yuzu.yuzu_emu.features.settings.model.LongSetting import org.yuzu.yuzu_emu.features.settings.model.Settings import org.yuzu.yuzu_emu.features.settings.model.Settings.MenuTag import org.yuzu.yuzu_emu.features.settings.model.ShortSetting +import org.yuzu.yuzu_emu.features.settings.model.StringSetting import org.yuzu.yuzu_emu.features.settings.model.view.* import org.yuzu.yuzu_emu.utils.InputHandler import org.yuzu.yuzu_emu.utils.NativeConfig @@ -153,6 +154,7 @@ class SettingsFragmentPresenter( private fun addSystemSettings(sl: ArrayList<SettingsItem>) { sl.apply { + add(StringSetting.DEVICE_NAME.key) add(BooleanSetting.RENDERER_USE_SPEED_LIMIT.key) add(ShortSetting.RENDERER_SPEED_LIMIT.key) add(BooleanSetting.USE_DOCKED_MODE.key) @@ -778,7 +780,7 @@ class SettingsFragmentPresenter( playerIndex: Int, paramName: String, stick: NativeAnalog, - defaultValue: Int + defaultValue: Float ): AbstractIntSetting = object : AbstractIntSetting { val params get() = NativeInput.getStickParam(playerIndex, stick) @@ -786,7 +788,7 @@ class SettingsFragmentPresenter( override val key = "" override fun getInt(needsGlobal: Boolean): Int = - (params.get(paramName, 0.15f) * 100).toInt() + (params.get(paramName, defaultValue) * 100).toInt() override fun setInt(value: Int) { val tempParams = params @@ -794,12 +796,12 @@ class SettingsFragmentPresenter( NativeInput.setStickParam(playerIndex, stick, tempParams) } - override val defaultValue = defaultValue + override val defaultValue = (defaultValue * 100).toInt() override fun getValueAsString(needsGlobal: Boolean): String = getInt(needsGlobal).toString() - override fun reset() = setInt(defaultValue) + override fun reset() = setInt(this.defaultValue) } private fun getExtraStickSettings( @@ -809,11 +811,11 @@ class SettingsFragmentPresenter( val stickIsController = NativeInput.isController(NativeInput.getStickParam(playerIndex, nativeAnalog)) val modifierRangeSetting = - getStickIntSettingFromParam(playerIndex, "modifier_scale", nativeAnalog, 50) + getStickIntSettingFromParam(playerIndex, "modifier_scale", nativeAnalog, 0.5f) val stickRangeSetting = - getStickIntSettingFromParam(playerIndex, "range", nativeAnalog, 95) + getStickIntSettingFromParam(playerIndex, "range", nativeAnalog, 0.95f) val stickDeadzoneSetting = - getStickIntSettingFromParam(playerIndex, "deadzone", nativeAnalog, 15) + getStickIntSettingFromParam(playerIndex, "deadzone", nativeAnalog, 0.15f) val out = mutableListOf<SettingsItem>().apply { if (stickIsController) { diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt index 367db7fd2..0309fad59 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt @@ -13,7 +13,6 @@ import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding import org.yuzu.yuzu_emu.features.settings.model.view.DateTimeSetting import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter -import org.yuzu.yuzu_emu.utils.NativeConfig import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : @@ -32,9 +31,7 @@ class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM) binding.textSettingValue.text = dateFormatter.format(zonedTime) - binding.buttonClear.setVisible( - !setting.setting.global || NativeConfig.isPerGameConfigLoaded() - ) + binding.buttonClear.setVisible(setting.clearable) binding.buttonClear.setOnClickListener { adapter.onClearClick(setting, bindingAdapterPosition) } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt index e2fe0b072..489f55455 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt @@ -10,7 +10,6 @@ import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter -import org.yuzu.yuzu_emu.utils.NativeConfig import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : @@ -48,9 +47,7 @@ class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Setti binding.textSettingValue.setVisible(false) } - binding.buttonClear.setVisible( - !setting.setting.global || NativeConfig.isPerGameConfigLoaded() - ) + binding.buttonClear.setVisible(setting.clearable) binding.buttonClear.setOnClickListener { adapter.onClearClick(setting, bindingAdapterPosition) } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt index a37b59b44..90a7138cb 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt @@ -9,7 +9,6 @@ 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.SliderSetting import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter -import org.yuzu.yuzu_emu.utils.NativeConfig import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : @@ -28,9 +27,7 @@ class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAda setting.units ) - binding.buttonClear.setVisible( - !setting.setting.global || NativeConfig.isPerGameConfigLoaded() - ) + binding.buttonClear.setVisible(setting.clearable) binding.buttonClear.setOnClickListener { adapter.onClearClick(setting, bindingAdapterPosition) } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/StringInputViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/StringInputViewHolder.kt new file mode 100644 index 000000000..a4fd36f62 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/StringInputViewHolder.kt @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.yuzu.yuzu_emu.features.settings.ui.viewholder + +import android.view.View +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.StringInputSetting +import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter +import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible + +class StringInputViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : + SettingViewHolder(binding.root, adapter) { + private lateinit var setting: StringInputSetting + + override fun bind(item: SettingsItem) { + setting = item as StringInputSetting + binding.textSettingName.text = setting.title + binding.textSettingDescription.setVisible(setting.description.isNotEmpty()) + binding.textSettingDescription.text = setting.description + binding.textSettingValue.setVisible(true) + binding.textSettingValue.text = setting.getSelectedValue() + + binding.buttonClear.setVisible(setting.clearable) + binding.buttonClear.setOnClickListener { + adapter.onClearClick(setting, bindingAdapterPosition) + } + + setStyle(setting.isEditable, binding) + } + + override fun onClick(clicked: View) { + if (setting.isEditable) { + adapter.onStringInputClick(setting, bindingAdapterPosition) + } + } + + override fun onLongClick(clicked: View): Boolean { + if (setting.isEditable) { + return adapter.onLongClick(setting, bindingAdapterPosition) + } + return false + } +} diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt index 53f7b301f..e5763264a 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt @@ -9,7 +9,6 @@ import org.yuzu.yuzu_emu.databinding.ListItemSettingSwitchBinding import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.model.view.SwitchSetting import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter -import org.yuzu.yuzu_emu.utils.NativeConfig import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter: SettingsAdapter) : @@ -29,9 +28,7 @@ class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter adapter.onBooleanClick(setting, binding.switchWidget.isChecked, bindingAdapterPosition) } - binding.buttonClear.setVisible( - !setting.setting.global || NativeConfig.isPerGameConfigLoaded() - ) + binding.buttonClear.setVisible(setting.clearable) binding.buttonClear.setOnClickListener { adapter.onClearClick(setting, bindingAdapterPosition) } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt index c3b2b11f8..bcc880e17 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt @@ -810,7 +810,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { } } } - binding.doneControlConfig.setVisible(false) + binding.doneControlConfig.setVisible(true) binding.surfaceInputOverlay.setIsInEditMode(true) } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt index 66907085a..737e03584 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt @@ -28,6 +28,7 @@ import org.yuzu.yuzu_emu.features.input.NativeInput import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.features.input.model.NativeAnalog import org.yuzu.yuzu_emu.features.input.model.NativeButton +import org.yuzu.yuzu_emu.features.input.model.NpadStyleIndex import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting import org.yuzu.yuzu_emu.features.settings.model.IntSetting import org.yuzu.yuzu_emu.overlay.model.OverlayControl @@ -99,12 +100,10 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : } var shouldUpdateView = false - val playerIndex = - if (NativeInput.isHandheldOnly()) { - NativeInput.ConsoleDevice - } else { - NativeInput.Player1Device - } + val playerIndex = when (NativeInput.getStyleIndex(0)) { + NpadStyleIndex.Handheld -> 8 + else -> 0 + } for (button in overlayButtons) { if (!button.updateStatus(event)) { @@ -664,7 +663,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : val overlayControlData = NativeConfig.getOverlayControlData() overlayControlData.forEach { - it.enabled = OverlayControl.from(it.id)?.defaultVisibility == false + it.enabled = OverlayControl.from(it.id)?.defaultVisibility == true } NativeConfig.setOverlayControlData(overlayControlData) diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index 4ea82e217..1226219ad 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -292,6 +292,9 @@ void EmulationSession::ShutdownEmulation() { // Unload user input. m_system.HIDCore().UnloadInputDevices(); + // Enable all controllers + m_system.HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All}); + // Shutdown the main emulated process if (m_load_result == Core::SystemResultStatus::Success) { m_system.DetachDebugger(); diff --git a/src/android/app/src/main/jni/native_input.cpp b/src/android/app/src/main/jni/native_input.cpp index 37a65f2b8..4935a4607 100644 --- a/src/android/app/src/main/jni/native_input.cpp +++ b/src/android/app/src/main/jni/native_input.cpp @@ -102,8 +102,50 @@ void ApplyControllerConfig(size_t player_index, } } +std::vector<s32> GetSupportedStyles(int player_index) { + auto& hid_core = EmulationSession::GetInstance().System().HIDCore(); + const auto npad_style_set = hid_core.GetSupportedStyleTag(); + std::vector<s32> supported_indexes; + if (npad_style_set.fullkey == 1) { + supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::Fullkey)); + } + + if (npad_style_set.joycon_dual == 1) { + supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::JoyconDual)); + } + + if (npad_style_set.joycon_left == 1) { + supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::JoyconLeft)); + } + + if (npad_style_set.joycon_right == 1) { + supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::JoyconRight)); + } + + if (player_index == 0 && npad_style_set.handheld == 1) { + supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::Handheld)); + } + + if (npad_style_set.gamecube == 1) { + supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::GameCube)); + } + + return supported_indexes; +} + void ConnectController(size_t player_index, bool connected) { auto& hid_core = EmulationSession::GetInstance().System().HIDCore(); + ApplyControllerConfig(player_index, [&](Core::HID::EmulatedController* controller) { + auto supported_styles = GetSupportedStyles(player_index); + auto controller_style = controller->GetNpadStyleIndex(true); + auto style = std::find(supported_styles.begin(), supported_styles.end(), + static_cast<int>(controller_style)); + if (style == supported_styles.end() && !supported_styles.empty()) { + controller->SetNpadStyleIndex( + static_cast<Core::HID::NpadStyleIndex>(supported_styles[0])); + } + }); + if (player_index == 0) { auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); auto* player_one = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); @@ -522,36 +564,10 @@ jint Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getButtonNameImpl(JNIEnv jintArray Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getSupportedStyleTagsImpl( JNIEnv* env, jobject j_obj, jint j_player_index) { - auto& hid_core = EmulationSession::GetInstance().System().HIDCore(); - const auto npad_style_set = hid_core.GetSupportedStyleTag(); - std::vector<s32> supported_indexes; - if (npad_style_set.fullkey == 1) { - supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::Fullkey)); - } - - if (npad_style_set.joycon_dual == 1) { - supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::JoyconDual)); - } - - if (npad_style_set.joycon_left == 1) { - supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::JoyconLeft)); - } - - if (npad_style_set.joycon_right == 1) { - supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::JoyconRight)); - } - - if (j_player_index == 0 && npad_style_set.handheld == 1) { - supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::Handheld)); - } - - if (npad_style_set.gamecube == 1) { - supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::GameCube)); - } - - jintArray j_supported_indexes = env->NewIntArray(supported_indexes.size()); - env->SetIntArrayRegion(j_supported_indexes, 0, supported_indexes.size(), - supported_indexes.data()); + auto supported_styles = GetSupportedStyles(j_player_index); + jintArray j_supported_indexes = env->NewIntArray(supported_styles.size()); + env->SetIntArrayRegion(j_supported_indexes, 0, supported_styles.size(), + supported_styles.data()); return j_supported_indexes; } diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 6a631f664..f7f19cdad 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -209,6 +209,7 @@ <string name="value_with_units">%1$s%2$s</string> <!-- System settings strings --> + <string name="device_name">Device name</string> <string name="use_docked_mode">Docked Mode</string> <string name="use_docked_mode_description">Increases resolution, decreasing performance. Handheld Mode is used when disabled, lowering resolution and increasing performance.</string> <string name="emulated_region">Emulated region</string> diff --git a/src/common/settings.h b/src/common/settings.h index aa054dc24..b2b071e7e 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -384,6 +384,12 @@ struct Values { AstcRecompression::Bc3, "astc_recompression", Category::RendererAdvanced}; + SwitchableSetting<VramUsageMode, true> vram_usage_mode{linkage, + VramUsageMode::Conservative, + VramUsageMode::Conservative, + VramUsageMode::Aggressive, + "vram_usage_mode", + Category::RendererAdvanced}; SwitchableSetting<bool> async_presentation{linkage, #ifdef ANDROID true, diff --git a/src/common/settings_enums.h b/src/common/settings_enums.h index f42367e67..6e247e930 100644 --- a/src/common/settings_enums.h +++ b/src/common/settings_enums.h @@ -122,6 +122,8 @@ ENUM(AstcRecompression, Uncompressed, Bc1, Bc3); ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed); +ENUM(VramUsageMode, Conservative, Aggressive); + ENUM(RendererBackend, OpenGL, Vulkan, Null); ENUM(ShaderBackend, Glsl, Glasm, SpirV); diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 24dcc405f..cfce352c9 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -547,6 +547,16 @@ add_library(core STATIC hle/service/btdrv/btdrv.h hle/service/btm/btm.cpp hle/service/btm/btm.h + hle/service/btm/btm_debug.cpp + hle/service/btm/btm_debug.h + hle/service/btm/btm_system.cpp + hle/service/btm/btm_system.h + hle/service/btm/btm_system_core.cpp + hle/service/btm/btm_system_core.h + hle/service/btm/btm_user.cpp + hle/service/btm/btm_user.h + hle/service/btm/btm_user_core.cpp + hle/service/btm/btm_user_core.h hle/service/caps/caps.cpp hle/service/caps/caps.h hle/service/caps/caps_a.cpp diff --git a/src/core/device_memory_manager.inc b/src/core/device_memory_manager.inc index 37c1e69c3..f104d495b 100644 --- a/src/core/device_memory_manager.inc +++ b/src/core/device_memory_manager.inc @@ -522,13 +522,17 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size auto* memory_device_inter = registered_processes[asid.id]; const auto release_pending = [&] { if (uncache_bytes > 0) { - MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, - uncache_bytes, false); + if (memory_device_inter != nullptr) { + MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, + uncache_bytes, false); + } uncache_bytes = 0; } if (cache_bytes > 0) { - MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, - cache_bytes, true); + if (memory_device_inter != nullptr) { + MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, + cache_bytes, true); + } cache_bytes = 0; } }; diff --git a/src/core/file_sys/fssystem/fssystem_aes_xts_storage.h b/src/core/file_sys/fssystem/fssystem_aes_xts_storage.h index f342efb57..0e83ca1b9 100644 --- a/src/core/file_sys/fssystem/fssystem_aes_xts_storage.h +++ b/src/core/file_sys/fssystem/fssystem_aes_xts_storage.h @@ -3,6 +3,7 @@ #pragma once +#include <mutex> #include <optional> #include "core/crypto/aes_util.h" diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp index 2dc23e674..d120dade8 100644 --- a/src/core/hle/service/btm/btm.cpp +++ b/src/core/hle/service/btm/btm.cpp @@ -3,141 +3,18 @@ #include <memory> -#include "common/logging/log.h" -#include "core/core.h" -#include "core/hle/kernel/k_event.h" #include "core/hle/service/btm/btm.h" -#include "core/hle/service/ipc_helpers.h" -#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/btm/btm_debug.h" +#include "core/hle/service/btm/btm_system.h" +#include "core/hle/service/btm/btm_user.h" #include "core/hle/service/server_manager.h" #include "core/hle/service/service.h" namespace Service::BTM { -class IBtmUserCore final : public ServiceFramework<IBtmUserCore> { +class IBtm final : public ServiceFramework<IBtm> { public: - explicit IBtmUserCore(Core::System& system_) - : ServiceFramework{system_, "IBtmUserCore"}, service_context{system_, "IBtmUserCore"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &IBtmUserCore::AcquireBleScanEvent, "AcquireBleScanEvent"}, - {1, nullptr, "GetBleScanFilterParameter"}, - {2, nullptr, "GetBleScanFilterParameter2"}, - {3, nullptr, "StartBleScanForGeneral"}, - {4, nullptr, "StopBleScanForGeneral"}, - {5, nullptr, "GetBleScanResultsForGeneral"}, - {6, nullptr, "StartBleScanForPaired"}, - {7, nullptr, "StopBleScanForPaired"}, - {8, nullptr, "StartBleScanForSmartDevice"}, - {9, nullptr, "StopBleScanForSmartDevice"}, - {10, nullptr, "GetBleScanResultsForSmartDevice"}, - {17, &IBtmUserCore::AcquireBleConnectionEvent, "AcquireBleConnectionEvent"}, - {18, nullptr, "BleConnect"}, - {19, nullptr, "BleDisconnect"}, - {20, nullptr, "BleGetConnectionState"}, - {21, nullptr, "AcquireBlePairingEvent"}, - {22, nullptr, "BlePairDevice"}, - {23, nullptr, "BleUnPairDevice"}, - {24, nullptr, "BleUnPairDevice2"}, - {25, nullptr, "BleGetPairedDevices"}, - {26, &IBtmUserCore::AcquireBleServiceDiscoveryEvent, "AcquireBleServiceDiscoveryEvent"}, - {27, nullptr, "GetGattServices"}, - {28, nullptr, "GetGattService"}, - {29, nullptr, "GetGattIncludedServices"}, - {30, nullptr, "GetBelongingGattService"}, - {31, nullptr, "GetGattCharacteristics"}, - {32, nullptr, "GetGattDescriptors"}, - {33, &IBtmUserCore::AcquireBleMtuConfigEvent, "AcquireBleMtuConfigEvent"}, - {34, nullptr, "ConfigureBleMtu"}, - {35, nullptr, "GetBleMtu"}, - {36, nullptr, "RegisterBleGattDataPath"}, - {37, nullptr, "UnregisterBleGattDataPath"}, - }; - // clang-format on - RegisterHandlers(functions); - - scan_event = service_context.CreateEvent("IBtmUserCore:ScanEvent"); - connection_event = service_context.CreateEvent("IBtmUserCore:ConnectionEvent"); - service_discovery_event = service_context.CreateEvent("IBtmUserCore:DiscoveryEvent"); - config_event = service_context.CreateEvent("IBtmUserCore:ConfigEvent"); - } - - ~IBtmUserCore() override { - service_context.CloseEvent(scan_event); - service_context.CloseEvent(connection_event); - service_context.CloseEvent(service_discovery_event); - service_context.CloseEvent(config_event); - } - -private: - void AcquireBleScanEvent(HLERequestContext& ctx) { - LOG_WARNING(Service_BTM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3, 1}; - rb.Push(ResultSuccess); - rb.Push(true); - rb.PushCopyObjects(scan_event->GetReadableEvent()); - } - - void AcquireBleConnectionEvent(HLERequestContext& ctx) { - LOG_WARNING(Service_BTM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3, 1}; - rb.Push(ResultSuccess); - rb.Push(true); - rb.PushCopyObjects(connection_event->GetReadableEvent()); - } - - void AcquireBleServiceDiscoveryEvent(HLERequestContext& ctx) { - LOG_WARNING(Service_BTM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3, 1}; - rb.Push(ResultSuccess); - rb.Push(true); - rb.PushCopyObjects(service_discovery_event->GetReadableEvent()); - } - - void AcquireBleMtuConfigEvent(HLERequestContext& ctx) { - LOG_WARNING(Service_BTM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3, 1}; - rb.Push(ResultSuccess); - rb.Push(true); - rb.PushCopyObjects(config_event->GetReadableEvent()); - } - - KernelHelpers::ServiceContext service_context; - - Kernel::KEvent* scan_event; - Kernel::KEvent* connection_event; - Kernel::KEvent* service_discovery_event; - Kernel::KEvent* config_event; -}; - -class BTM_USR final : public ServiceFramework<BTM_USR> { -public: - explicit BTM_USR(Core::System& system_) : ServiceFramework{system_, "btm:u"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &BTM_USR::GetCore, "GetCore"}, - }; - // clang-format on - RegisterHandlers(functions); - } - -private: - void GetCore(HLERequestContext& ctx) { - LOG_WARNING(Service_BTM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IBtmUserCore>(system); - } -}; - -class BTM final : public ServiceFramework<BTM> { -public: - explicit BTM(Core::System& system_) : ServiceFramework{system_, "btm"} { + explicit IBtm(Core::System& system_) : ServiceFramework{system_, "btm"} { // clang-format off static const FunctionInfo functions[] = { {0, nullptr, "GetState"}, @@ -232,144 +109,13 @@ public: } }; -class BTM_DBG final : public ServiceFramework<BTM_DBG> { -public: - explicit BTM_DBG(Core::System& system_) : ServiceFramework{system_, "btm:dbg"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "AcquireDiscoveryEvent"}, - {1, nullptr, "StartDiscovery"}, - {2, nullptr, "CancelDiscovery"}, - {3, nullptr, "GetDeviceProperty"}, - {4, nullptr, "CreateBond"}, - {5, nullptr, "CancelBond"}, - {6, nullptr, "SetTsiMode"}, - {7, nullptr, "GeneralTest"}, - {8, nullptr, "HidConnect"}, - {9, nullptr, "GeneralGet"}, - {10, nullptr, "GetGattClientDisconnectionReason"}, - {11, nullptr, "GetBleConnectionParameter"}, - {12, nullptr, "GetBleConnectionParameterRequest"}, - {13, nullptr, "Unknown13"}, - }; - // clang-format on - - RegisterHandlers(functions); - } -}; - -class IBtmSystemCore final : public ServiceFramework<IBtmSystemCore> { -public: - explicit IBtmSystemCore(Core::System& system_) : ServiceFramework{system_, "IBtmSystemCore"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &IBtmSystemCore::StartGamepadPairing, "StartGamepadPairing"}, - {1, &IBtmSystemCore::CancelGamepadPairing, "CancelGamepadPairing"}, - {2, nullptr, "ClearGamepadPairingDatabase"}, - {3, nullptr, "GetPairedGamepadCount"}, - {4, nullptr, "EnableRadio"}, - {5, nullptr, "DisableRadio"}, - {6, &IBtmSystemCore::IsRadioEnabled, "IsRadioEnabled"}, - {7, nullptr, "AcquireRadioEvent"}, - {8, nullptr, "AcquireGamepadPairingEvent"}, - {9, nullptr, "IsGamepadPairingStarted"}, - {10, nullptr, "StartAudioDeviceDiscovery"}, - {11, nullptr, "StopAudioDeviceDiscovery"}, - {12, nullptr, "IsDiscoveryingAudioDevice"}, - {13, nullptr, "GetDiscoveredAudioDevice"}, - {14, nullptr, "AcquireAudioDeviceConnectionEvent"}, - {15, nullptr, "ConnectAudioDevice"}, - {16, nullptr, "IsConnectingAudioDevice"}, - {17, &IBtmSystemCore::GetConnectedAudioDevices, "GetConnectedAudioDevices"}, - {18, nullptr, "DisconnectAudioDevice"}, - {19, nullptr, "AcquirePairedAudioDeviceInfoChangedEvent"}, - {20, &IBtmSystemCore::GetPairedAudioDevices, "GetPairedAudioDevices"}, - {21, nullptr, "RemoveAudioDevicePairing"}, - {22, &IBtmSystemCore::RequestAudioDeviceConnectionRejection, "RequestAudioDeviceConnectionRejection"}, - {23, &IBtmSystemCore::CancelAudioDeviceConnectionRejection, "CancelAudioDeviceConnectionRejection"} - }; - // clang-format on - - RegisterHandlers(functions); - } - -private: - void IsRadioEnabled(HLERequestContext& ctx) { - LOG_DEBUG(Service_BTM, "(STUBBED) called"); // Spams a lot when controller applet is running - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(true); - } - - void StartGamepadPairing(HLERequestContext& ctx) { - LOG_WARNING(Service_BTM, "(STUBBED) called"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void CancelGamepadPairing(HLERequestContext& ctx) { - LOG_WARNING(Service_BTM, "(STUBBED) called"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void CancelAudioDeviceConnectionRejection(HLERequestContext& ctx) { - LOG_WARNING(Service_BTM, "(STUBBED) called"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void GetConnectedAudioDevices(HLERequestContext& ctx) { - LOG_WARNING(Service_BTM, "(STUBBED) called"); - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push<u32>(0); - } - - void GetPairedAudioDevices(HLERequestContext& ctx) { - LOG_WARNING(Service_BTM, "(STUBBED) called"); - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push<u32>(0); - } - - void RequestAudioDeviceConnectionRejection(HLERequestContext& ctx) { - LOG_WARNING(Service_BTM, "(STUBBED) called"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } -}; - -class BTM_SYS final : public ServiceFramework<BTM_SYS> { -public: - explicit BTM_SYS(Core::System& system_) : ServiceFramework{system_, "btm:sys"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &BTM_SYS::GetCore, "GetCore"}, - }; - // clang-format on - - RegisterHandlers(functions); - } - -private: - void GetCore(HLERequestContext& ctx) { - LOG_WARNING(Service_BTM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IBtmSystemCore>(system); - } -}; - void LoopProcess(Core::System& system) { auto server_manager = std::make_unique<ServerManager>(system); - server_manager->RegisterNamedService("btm", std::make_shared<BTM>(system)); - server_manager->RegisterNamedService("btm:dbg", std::make_shared<BTM_DBG>(system)); - server_manager->RegisterNamedService("btm:sys", std::make_shared<BTM_SYS>(system)); - server_manager->RegisterNamedService("btm:u", std::make_shared<BTM_USR>(system)); + server_manager->RegisterNamedService("btm", std::make_shared<IBtm>(system)); + server_manager->RegisterNamedService("btm:dbg", std::make_shared<IBtmDebug>(system)); + server_manager->RegisterNamedService("btm:sys", std::make_shared<IBtmSystem>(system)); + server_manager->RegisterNamedService("btm:u", std::make_shared<IBtmUser>(system)); ServerManager::RunServer(std::move(server_manager)); } diff --git a/src/core/hle/service/btm/btm.h b/src/core/hle/service/btm/btm.h index a99b34364..0bf77d053 100644 --- a/src/core/hle/service/btm/btm.h +++ b/src/core/hle/service/btm/btm.h @@ -3,10 +3,6 @@ #pragma once -namespace Service::SM { -class ServiceManager; -} - namespace Core { class System; }; diff --git a/src/core/hle/service/btm/btm_debug.cpp b/src/core/hle/service/btm/btm_debug.cpp new file mode 100644 index 000000000..4d61d2641 --- /dev/null +++ b/src/core/hle/service/btm/btm_debug.cpp @@ -0,0 +1,33 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "core/hle/service/btm/btm_debug.h" + +namespace Service::BTM { + +IBtmDebug::IBtmDebug(Core::System& system_) : ServiceFramework{system_, "btm:dbg"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "AcquireDiscoveryEvent"}, + {1, nullptr, "StartDiscovery"}, + {2, nullptr, "CancelDiscovery"}, + {3, nullptr, "GetDeviceProperty"}, + {4, nullptr, "CreateBond"}, + {5, nullptr, "CancelBond"}, + {6, nullptr, "SetTsiMode"}, + {7, nullptr, "GeneralTest"}, + {8, nullptr, "HidConnect"}, + {9, nullptr, "GeneralGet"}, + {10, nullptr, "GetGattClientDisconnectionReason"}, + {11, nullptr, "GetBleConnectionParameter"}, + {12, nullptr, "GetBleConnectionParameterRequest"}, + {13, nullptr, "Unknown13"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IBtmDebug::~IBtmDebug() = default; + +} // namespace Service::BTM diff --git a/src/core/hle/service/btm/btm_debug.h b/src/core/hle/service/btm/btm_debug.h new file mode 100644 index 000000000..bf4f7e14f --- /dev/null +++ b/src/core/hle/service/btm/btm_debug.h @@ -0,0 +1,21 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/service.h" + +namespace Core { +class System; +} + +namespace Service::BTM { + +class IBtmDebug final : public ServiceFramework<IBtmDebug> { +public: + explicit IBtmDebug(Core::System& system_); + ~IBtmDebug() override; +}; + +} // namespace Service::BTM diff --git a/src/core/hle/service/btm/btm_system.cpp b/src/core/hle/service/btm/btm_system.cpp new file mode 100644 index 000000000..99718a7b0 --- /dev/null +++ b/src/core/hle/service/btm/btm_system.cpp @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "common/logging/log.h" +#include "core/hle/service/btm/btm_system.h" +#include "core/hle/service/btm/btm_system_core.h" +#include "core/hle/service/cmif_serialization.h" +#include "core/hle/service/service.h" + +namespace Service::BTM { + +IBtmSystem::IBtmSystem(Core::System& system_) : ServiceFramework{system_, "btm:sys"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, C<&IBtmSystem::GetCore>, "GetCore"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IBtmSystem::~IBtmSystem() = default; + +Result IBtmSystem::GetCore(OutInterface<IBtmSystemCore> out_interface) { + LOG_WARNING(Service_BTM, "called"); + + *out_interface = std::make_shared<IBtmSystemCore>(system); + R_SUCCEED(); +} + +} // namespace Service::BTM diff --git a/src/core/hle/service/btm/btm_system.h b/src/core/hle/service/btm/btm_system.h new file mode 100644 index 000000000..fe1c6dbd7 --- /dev/null +++ b/src/core/hle/service/btm/btm_system.h @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/service.h" + +namespace Core { +class System; +} + +namespace Service::BTM { +class IBtmSystemCore; + +class IBtmSystem final : public ServiceFramework<IBtmSystem> { +public: + explicit IBtmSystem(Core::System& system_); + ~IBtmSystem() override; + +private: + Result GetCore(OutInterface<IBtmSystemCore> out_interface); +}; + +} // namespace Service::BTM diff --git a/src/core/hle/service/btm/btm_system_core.cpp b/src/core/hle/service/btm/btm_system_core.cpp new file mode 100644 index 000000000..4bc8a9e8b --- /dev/null +++ b/src/core/hle/service/btm/btm_system_core.cpp @@ -0,0 +1,127 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "common/logging/log.h" +#include "core/hle/service/btm/btm_system_core.h" +#include "core/hle/service/cmif_serialization.h" +#include "core/hle/service/set/system_settings_server.h" +#include "core/hle/service/sm/sm.h" + +namespace Service::BTM { + +IBtmSystemCore::IBtmSystemCore(Core::System& system_) + : ServiceFramework{system_, "IBtmSystemCore"}, service_context{system_, "IBtmSystemCore"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, C<&IBtmSystemCore::StartGamepadPairing>, "StartGamepadPairing"}, + {1, C<&IBtmSystemCore::CancelGamepadPairing>, "CancelGamepadPairing"}, + {2, nullptr, "ClearGamepadPairingDatabase"}, + {3, nullptr, "GetPairedGamepadCount"}, + {4, C<&IBtmSystemCore::EnableRadio>, "EnableRadio"}, + {5, C<&IBtmSystemCore::DisableRadio>, "DisableRadio"}, + {6, C<&IBtmSystemCore::IsRadioEnabled>, "IsRadioEnabled"}, + {7, C<&IBtmSystemCore::AcquireRadioEvent>, "AcquireRadioEvent"}, + {8, nullptr, "AcquireGamepadPairingEvent"}, + {9, nullptr, "IsGamepadPairingStarted"}, + {10, nullptr, "StartAudioDeviceDiscovery"}, + {11, nullptr, "StopAudioDeviceDiscovery"}, + {12, nullptr, "IsDiscoveryingAudioDevice"}, + {13, nullptr, "GetDiscoveredAudioDevice"}, + {14, C<&IBtmSystemCore::AcquireAudioDeviceConnectionEvent>, "AcquireAudioDeviceConnectionEvent"}, + {15, nullptr, "ConnectAudioDevice"}, + {16, nullptr, "IsConnectingAudioDevice"}, + {17, C<&IBtmSystemCore::GetConnectedAudioDevices>, "GetConnectedAudioDevices"}, + {18, nullptr, "DisconnectAudioDevice"}, + {19, nullptr, "AcquirePairedAudioDeviceInfoChangedEvent"}, + {20, C<&IBtmSystemCore::GetPairedAudioDevices>, "GetPairedAudioDevices"}, + {21, nullptr, "RemoveAudioDevicePairing"}, + {22, C<&IBtmSystemCore::RequestAudioDeviceConnectionRejection>, "RequestAudioDeviceConnectionRejection"}, + {23, C<&IBtmSystemCore::CancelAudioDeviceConnectionRejection>, "CancelAudioDeviceConnectionRejection"} + }; + // clang-format on + + RegisterHandlers(functions); + radio_event = service_context.CreateEvent("IBtmSystemCore::RadioEvent"); + audio_device_connection_event = + service_context.CreateEvent("IBtmSystemCore::AudioDeviceConnectionEvent"); + + m_set_sys = + system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true); +} + +IBtmSystemCore::~IBtmSystemCore() { + service_context.CloseEvent(radio_event); + service_context.CloseEvent(audio_device_connection_event); +} + +Result IBtmSystemCore::StartGamepadPairing() { + LOG_WARNING(Service_BTM, "(STUBBED) called"); + R_SUCCEED(); +} + +Result IBtmSystemCore::CancelGamepadPairing() { + LOG_WARNING(Service_BTM, "(STUBBED) called"); + R_SUCCEED(); +} + +Result IBtmSystemCore::EnableRadio() { + LOG_DEBUG(Service_BTM, "called"); + + R_RETURN(m_set_sys->SetBluetoothEnableFlag(true)); +} +Result IBtmSystemCore::DisableRadio() { + LOG_DEBUG(Service_BTM, "called"); + + R_RETURN(m_set_sys->SetBluetoothEnableFlag(false)); +} + +Result IBtmSystemCore::IsRadioEnabled(Out<bool> out_is_enabled) { + LOG_DEBUG(Service_BTM, "called"); + + R_RETURN(m_set_sys->GetBluetoothEnableFlag(out_is_enabled)); +} + +Result IBtmSystemCore::AcquireRadioEvent(Out<bool> out_is_valid, + OutCopyHandle<Kernel::KReadableEvent> out_event) { + LOG_WARNING(Service_BTM, "(STUBBED) called"); + + *out_is_valid = true; + *out_event = &radio_event->GetReadableEvent(); + R_SUCCEED(); +} + +Result IBtmSystemCore::AcquireAudioDeviceConnectionEvent( + OutCopyHandle<Kernel::KReadableEvent> out_event) { + LOG_WARNING(Service_BTM, "(STUBBED) called"); + + *out_event = &audio_device_connection_event->GetReadableEvent(); + R_SUCCEED(); +} + +Result IBtmSystemCore::GetConnectedAudioDevices( + Out<s32> out_count, OutArray<std::array<u8, 0xFF>, BufferAttr_HipcPointer> out_audio_devices) { + LOG_WARNING(Service_BTM, "(STUBBED) called"); + + *out_count = 0; + R_SUCCEED(); +} + +Result IBtmSystemCore::GetPairedAudioDevices( + Out<s32> out_count, OutArray<std::array<u8, 0xFF>, BufferAttr_HipcPointer> out_audio_devices) { + LOG_WARNING(Service_BTM, "(STUBBED) called"); + + *out_count = 0; + R_SUCCEED(); +} + +Result IBtmSystemCore::RequestAudioDeviceConnectionRejection(ClientAppletResourceUserId aruid) { + LOG_WARNING(Service_BTM, "(STUBBED) called, applet_resource_user_id={}", aruid.pid); + R_SUCCEED(); +} + +Result IBtmSystemCore::CancelAudioDeviceConnectionRejection(ClientAppletResourceUserId aruid) { + LOG_WARNING(Service_BTM, "(STUBBED) called, applet_resource_user_id={}", aruid.pid); + R_SUCCEED(); +} + +} // namespace Service::BTM diff --git a/src/core/hle/service/btm/btm_system_core.h b/src/core/hle/service/btm/btm_system_core.h new file mode 100644 index 000000000..06498b21e --- /dev/null +++ b/src/core/hle/service/btm/btm_system_core.h @@ -0,0 +1,60 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/service.h" + +namespace Kernel { +class KEvent; +class KReadableEvent; +} // namespace Kernel + +namespace Core { +class System; +} + +namespace Service::Set { +class ISystemSettingsServer; +} + +namespace Service::BTM { + +class IBtmSystemCore final : public ServiceFramework<IBtmSystemCore> { +public: + explicit IBtmSystemCore(Core::System& system_); + ~IBtmSystemCore() override; + +private: + Result StartGamepadPairing(); + Result CancelGamepadPairing(); + Result EnableRadio(); + Result DisableRadio(); + Result IsRadioEnabled(Out<bool> out_is_enabled); + + Result AcquireRadioEvent(Out<bool> out_is_valid, + OutCopyHandle<Kernel::KReadableEvent> out_event); + + Result AcquireAudioDeviceConnectionEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); + + Result GetConnectedAudioDevices( + Out<s32> out_count, + OutArray<std::array<u8, 0xFF>, BufferAttr_HipcPointer> out_audio_devices); + + Result GetPairedAudioDevices( + Out<s32> out_count, + OutArray<std::array<u8, 0xFF>, BufferAttr_HipcPointer> out_audio_devices); + + Result RequestAudioDeviceConnectionRejection(ClientAppletResourceUserId aruid); + Result CancelAudioDeviceConnectionRejection(ClientAppletResourceUserId aruid); + + KernelHelpers::ServiceContext service_context; + + Kernel::KEvent* radio_event; + Kernel::KEvent* audio_device_connection_event; + std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys; +}; + +} // namespace Service::BTM diff --git a/src/core/hle/service/btm/btm_user.cpp b/src/core/hle/service/btm/btm_user.cpp new file mode 100644 index 000000000..d2e228f8d --- /dev/null +++ b/src/core/hle/service/btm/btm_user.cpp @@ -0,0 +1,30 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "common/logging/log.h" +#include "core/hle/service/btm/btm_user.h" +#include "core/hle/service/btm/btm_user_core.h" +#include "core/hle/service/cmif_serialization.h" + +namespace Service::BTM { + +IBtmUser::IBtmUser(Core::System& system_) : ServiceFramework{system_, "btm:u"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, C<&IBtmUser::GetCore>, "GetCore"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IBtmUser::~IBtmUser() = default; + +Result IBtmUser::GetCore(OutInterface<IBtmUserCore> out_interface) { + LOG_WARNING(Service_BTM, "called"); + + *out_interface = std::make_shared<IBtmUserCore>(system); + R_SUCCEED(); +} + +} // namespace Service::BTM diff --git a/src/core/hle/service/btm/btm_user.h b/src/core/hle/service/btm/btm_user.h new file mode 100644 index 000000000..d9ee5db45 --- /dev/null +++ b/src/core/hle/service/btm/btm_user.h @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/service.h" + +namespace Core { +class System; +} + +namespace Service::BTM { +class IBtmUserCore; + +class IBtmUser final : public ServiceFramework<IBtmUser> { +public: + explicit IBtmUser(Core::System& system_); + ~IBtmUser() override; + +private: + Result GetCore(OutInterface<IBtmUserCore> out_interface); +}; + +} // namespace Service::BTM diff --git a/src/core/hle/service/btm/btm_user_core.cpp b/src/core/hle/service/btm/btm_user_core.cpp new file mode 100644 index 000000000..6f9fa589b --- /dev/null +++ b/src/core/hle/service/btm/btm_user_core.cpp @@ -0,0 +1,103 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include <memory> + +#include "common/logging/log.h" +#include "core/core.h" +#include "core/hle/kernel/k_event.h" +#include "core/hle/service/btm/btm_user_core.h" +#include "core/hle/service/cmif_serialization.h" + +namespace Service::BTM { + +IBtmUserCore::IBtmUserCore(Core::System& system_) + : ServiceFramework{system_, "IBtmUserCore"}, service_context{system_, "IBtmUserCore"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, C<&IBtmUserCore::AcquireBleScanEvent>, "AcquireBleScanEvent"}, + {1, nullptr, "GetBleScanFilterParameter"}, + {2, nullptr, "GetBleScanFilterParameter2"}, + {3, nullptr, "StartBleScanForGeneral"}, + {4, nullptr, "StopBleScanForGeneral"}, + {5, nullptr, "GetBleScanResultsForGeneral"}, + {6, nullptr, "StartBleScanForPaired"}, + {7, nullptr, "StopBleScanForPaired"}, + {8, nullptr, "StartBleScanForSmartDevice"}, + {9, nullptr, "StopBleScanForSmartDevice"}, + {10, nullptr, "GetBleScanResultsForSmartDevice"}, + {17, C<&IBtmUserCore::AcquireBleConnectionEvent>, "AcquireBleConnectionEvent"}, + {18, nullptr, "BleConnect"}, + {19, nullptr, "BleDisconnect"}, + {20, nullptr, "BleGetConnectionState"}, + {21, nullptr, "AcquireBlePairingEvent"}, + {22, nullptr, "BlePairDevice"}, + {23, nullptr, "BleUnPairDevice"}, + {24, nullptr, "BleUnPairDevice2"}, + {25, nullptr, "BleGetPairedDevices"}, + {26, C<&IBtmUserCore::AcquireBleServiceDiscoveryEvent>, "AcquireBleServiceDiscoveryEvent"}, + {27, nullptr, "GetGattServices"}, + {28, nullptr, "GetGattService"}, + {29, nullptr, "GetGattIncludedServices"}, + {30, nullptr, "GetBelongingGattService"}, + {31, nullptr, "GetGattCharacteristics"}, + {32, nullptr, "GetGattDescriptors"}, + {33, C<&IBtmUserCore::AcquireBleMtuConfigEvent>, "AcquireBleMtuConfigEvent"}, + {34, nullptr, "ConfigureBleMtu"}, + {35, nullptr, "GetBleMtu"}, + {36, nullptr, "RegisterBleGattDataPath"}, + {37, nullptr, "UnregisterBleGattDataPath"}, + }; + // clang-format on + RegisterHandlers(functions); + + scan_event = service_context.CreateEvent("IBtmUserCore:ScanEvent"); + connection_event = service_context.CreateEvent("IBtmUserCore:ConnectionEvent"); + service_discovery_event = service_context.CreateEvent("IBtmUserCore:DiscoveryEvent"); + config_event = service_context.CreateEvent("IBtmUserCore:ConfigEvent"); +} + +IBtmUserCore::~IBtmUserCore() { + service_context.CloseEvent(scan_event); + service_context.CloseEvent(connection_event); + service_context.CloseEvent(service_discovery_event); + service_context.CloseEvent(config_event); +} + +Result IBtmUserCore::AcquireBleScanEvent(Out<bool> out_is_valid, + OutCopyHandle<Kernel::KReadableEvent> out_event) { + LOG_WARNING(Service_BTM, "(STUBBED) called"); + + *out_is_valid = true; + *out_event = &scan_event->GetReadableEvent(); + R_SUCCEED(); +} + +Result IBtmUserCore::AcquireBleConnectionEvent(Out<bool> out_is_valid, + OutCopyHandle<Kernel::KReadableEvent> out_event) { + LOG_WARNING(Service_BTM, "(STUBBED) called"); + + *out_is_valid = true; + *out_event = &connection_event->GetReadableEvent(); + R_SUCCEED(); +} + +Result IBtmUserCore::AcquireBleServiceDiscoveryEvent( + Out<bool> out_is_valid, OutCopyHandle<Kernel::KReadableEvent> out_event) { + LOG_WARNING(Service_BTM, "(STUBBED) called"); + + *out_is_valid = true; + *out_event = &service_discovery_event->GetReadableEvent(); + R_SUCCEED(); +} + +Result IBtmUserCore::AcquireBleMtuConfigEvent(Out<bool> out_is_valid, + OutCopyHandle<Kernel::KReadableEvent> out_event) { + LOG_WARNING(Service_BTM, "(STUBBED) called"); + + *out_is_valid = true; + *out_event = &config_event->GetReadableEvent(); + R_SUCCEED(); +} + +} // namespace Service::BTM diff --git a/src/core/hle/service/btm/btm_user_core.h b/src/core/hle/service/btm/btm_user_core.h new file mode 100644 index 000000000..dc0a22e81 --- /dev/null +++ b/src/core/hle/service/btm/btm_user_core.h @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/service.h" + +namespace Kernel { +class KEvent; +class KReadableEvent; +} // namespace Kernel + +namespace Core { +class System; +} + +namespace Service::BTM { + +class IBtmUserCore final : public ServiceFramework<IBtmUserCore> { +public: + explicit IBtmUserCore(Core::System& system_); + ~IBtmUserCore() override; + +private: + Result AcquireBleScanEvent(Out<bool> out_is_valid, + OutCopyHandle<Kernel::KReadableEvent> out_event); + + Result AcquireBleConnectionEvent(Out<bool> out_is_valid, + OutCopyHandle<Kernel::KReadableEvent> out_event); + + Result AcquireBleServiceDiscoveryEvent(Out<bool> out_is_valid, + OutCopyHandle<Kernel::KReadableEvent> out_event); + + Result AcquireBleMtuConfigEvent(Out<bool> out_is_valid, + OutCopyHandle<Kernel::KReadableEvent> out_event); + + KernelHelpers::ServiceContext service_context; + + Kernel::KEvent* scan_event; + Kernel::KEvent* connection_event; + Kernel::KEvent* service_discovery_event; + Kernel::KEvent* config_event; +}; + +} // namespace Service::BTM diff --git a/src/core/hle/service/ns/application_manager_interface.cpp b/src/core/hle/service/ns/application_manager_interface.cpp index 2e3a44c0d..7a91727f9 100644 --- a/src/core/hle/service/ns/application_manager_interface.cpp +++ b/src/core/hle/service/ns/application_manager_interface.cpp @@ -436,14 +436,14 @@ Result IApplicationManagerInterface::GetApplicationViewWithPromotionInfo( Result IApplicationManagerInterface::GetApplicationRightsOnClient( OutArray<ApplicationRightsOnClient, BufferAttr_HipcMapAlias> out_rights, Out<u32> out_count, - Common::UUID account_id, u32 flags, u64 application_id) { + u32 flags, u64 application_id, Uid account_id) { LOG_WARNING(Service_NS, "(STUBBED) called, flags={}, application_id={:016X}, account_id={}", - flags, application_id, account_id.FormattedString()); + flags, application_id, account_id.uuid.FormattedString()); if (!out_rights.empty()) { ApplicationRightsOnClient rights{}; rights.application_id = application_id; - rights.uid = account_id; + rights.uid = account_id.uuid; rights.flags = 0; rights.flags2 = 0; diff --git a/src/core/hle/service/ns/application_manager_interface.h b/src/core/hle/service/ns/application_manager_interface.h index 350ec37ce..f33d269b3 100644 --- a/src/core/hle/service/ns/application_manager_interface.h +++ b/src/core/hle/service/ns/application_manager_interface.h @@ -37,7 +37,7 @@ public: InArray<u64, BufferAttr_HipcMapAlias> application_ids); Result GetApplicationRightsOnClient( OutArray<ApplicationRightsOnClient, BufferAttr_HipcMapAlias> out_rights, Out<u32> out_count, - Common::UUID account_id, u32 flags, u64 application_id); + u32 flags, u64 application_id, Uid account_id); Result CheckSdCardMountStatus(); Result GetSdCardMountStatusChangedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); Result GetFreeSpaceSize(Out<s64> out_free_space_size, FileSys::StorageId storage_id); diff --git a/src/core/hle/service/ns/ns_types.h b/src/core/hle/service/ns/ns_types.h index 38421b0f4..2dd664c4e 100644 --- a/src/core/hle/service/ns/ns_types.h +++ b/src/core/hle/service/ns/ns_types.h @@ -108,4 +108,9 @@ struct ContentPath { }; static_assert(sizeof(ContentPath) == 0x10, "ContentPath has incorrect size."); +struct Uid { + alignas(8) Common::UUID uuid; +}; +static_assert(sizeof(Uid) == 0x10, "Uid has incorrect size."); + } // namespace Service::NS diff --git a/src/core/hle/service/ns/query_service.cpp b/src/core/hle/service/ns/query_service.cpp index 946b7fa23..138400541 100644 --- a/src/core/hle/service/ns/query_service.cpp +++ b/src/core/hle/service/ns/query_service.cpp @@ -41,8 +41,7 @@ IQueryService::IQueryService(Core::System& system_) : ServiceFramework{system_, IQueryService::~IQueryService() = default; Result IQueryService::QueryPlayStatisticsByApplicationIdAndUserAccountId( - Out<PlayStatistics> out_play_statistics, bool unknown, Common::UUID account_id, - u64 application_id) { + Out<PlayStatistics> out_play_statistics, bool unknown, u64 application_id, Uid account_id) { // TODO(German77): Read statistics of the game *out_play_statistics = { .application_id = application_id, @@ -50,7 +49,7 @@ Result IQueryService::QueryPlayStatisticsByApplicationIdAndUserAccountId( }; LOG_WARNING(Service_NS, "(STUBBED) called. unknown={}. application_id={:016X}, account_id={}", - unknown, application_id, account_id.FormattedString()); + unknown, application_id, account_id.uuid.FormattedString()); R_SUCCEED(); } diff --git a/src/core/hle/service/ns/query_service.h b/src/core/hle/service/ns/query_service.h index 6cdbfa277..c4c82b752 100644 --- a/src/core/hle/service/ns/query_service.h +++ b/src/core/hle/service/ns/query_service.h @@ -5,6 +5,7 @@ #include "common/uuid.h" #include "core/hle/service/cmif_types.h" +#include "core/hle/service/ns/ns_types.h" #include "core/hle/service/service.h" namespace Service::NS { @@ -29,8 +30,7 @@ public: private: Result QueryPlayStatisticsByApplicationIdAndUserAccountId( - Out<PlayStatistics> out_play_statistics, bool unknown, Common::UUID account_id, - u64 application_id); + Out<PlayStatistics> out_play_statistics, bool unknown, u64 application_id, Uid account_id); }; } // namespace Service::NS diff --git a/src/core/hle/service/nvnflinger/display.h b/src/core/hle/service/nvnflinger/display.h index f27cbf144..40aa59787 100644 --- a/src/core/hle/service/nvnflinger/display.h +++ b/src/core/hle/service/nvnflinger/display.h @@ -3,8 +3,6 @@ #pragma once -#include <list> - #include "core/hle/service/nvnflinger/buffer_item_consumer.h" #include "core/hle/service/nvnflinger/hwc_layer.h" @@ -26,18 +24,12 @@ struct Layer { }; struct LayerStack { - std::list<Layer> layers; -}; - -struct Display { - explicit Display(u64 id_) { - id = id_; - } + std::vector<std::shared_ptr<Layer>> layers; - Layer* FindLayer(s32 consumer_id) { - for (auto& layer : stack.layers) { - if (layer.consumer_id == consumer_id) { - return &layer; + std::shared_ptr<Layer> FindLayer(s32 consumer_id) { + for (auto& layer : layers) { + if (layer->consumer_id == consumer_id) { + return layer; } } @@ -45,7 +37,13 @@ struct Display { } bool HasLayers() { - return !stack.layers.empty(); + return !layers.empty(); + } +}; + +struct Display { + explicit Display(u64 id_) { + id = id_; } u64 id; diff --git a/src/core/hle/service/nvnflinger/hardware_composer.cpp b/src/core/hle/service/nvnflinger/hardware_composer.cpp index 02215a786..f2dfe85a9 100644 --- a/src/core/hle/service/nvnflinger/hardware_composer.cpp +++ b/src/core/hle/service/nvnflinger/hardware_composer.cpp @@ -55,10 +55,10 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display, // Acquire all necessary framebuffers. for (auto& layer : display.stack.layers) { - auto consumer_id = layer.consumer_id; + auto consumer_id = layer->consumer_id; // Try to fetch the framebuffer (either new or stale). - const auto result = this->CacheFramebufferLocked(layer, consumer_id); + const auto result = this->CacheFramebufferLocked(*layer, consumer_id); // If we failed, skip this layer. if (result == CacheStatus::NoBufferAvailable) { @@ -75,7 +75,7 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display, const auto& igbp_buffer = *item.graphic_buffer; // TODO: get proper Z-index from layer - if (layer.visible) { + if (layer->visible) { composition_stack.emplace_back(HwcLayer{ .buffer_handle = igbp_buffer.BufferId(), .offset = igbp_buffer.Offset(), @@ -84,7 +84,7 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display, .height = igbp_buffer.Height(), .stride = igbp_buffer.Stride(), .z_index = 0, - .blending = layer.blending, + .blending = layer->blending, .transform = static_cast<android::BufferTransformFlags>(item.transform), .crop_rect = item.crop, .acquire_fence = item.fence, @@ -134,7 +134,7 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display, continue; } - if (auto* layer = display.FindLayer(layer_id); layer != nullptr) { + if (const auto layer = display.stack.FindLayer(layer_id); layer != nullptr) { // TODO: support release fence // This is needed to prevent screen tearing layer->buffer_item_consumer->ReleaseBuffer(framebuffer.item, android::Fence::NoFence()); @@ -153,7 +153,7 @@ void HardwareComposer::RemoveLayerLocked(Display& display, ConsumerId consumer_i } // Try to release the buffer item. - auto* const layer = display.FindLayer(consumer_id); + const auto layer = display.stack.FindLayer(consumer_id); if (layer && it->second.is_acquired) { layer->buffer_item_consumer->ReleaseBuffer(it->second.item, android::Fence::NoFence()); } diff --git a/src/core/hle/service/nvnflinger/surface_flinger.cpp b/src/core/hle/service/nvnflinger/surface_flinger.cpp index 41a705717..8362b65e5 100644 --- a/src/core/hle/service/nvnflinger/surface_flinger.cpp +++ b/src/core/hle/service/nvnflinger/surface_flinger.cpp @@ -36,7 +36,7 @@ void SurfaceFlinger::RemoveDisplay(u64 display_id) { bool SurfaceFlinger::ComposeDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, u64 display_id) { auto* const display = this->FindDisplay(display_id); - if (!display || !display->HasLayers()) { + if (!display || !display->stack.HasLayers()) { return false; } @@ -46,19 +46,34 @@ bool SurfaceFlinger::ComposeDisplay(s32* out_swap_interval, f32* out_compose_spe return true; } -void SurfaceFlinger::AddLayerToDisplayStack(u64 display_id, s32 consumer_binder_id) { - auto* const display = this->FindDisplay(display_id); +void SurfaceFlinger::CreateLayer(s32 consumer_binder_id) { auto binder = std::static_pointer_cast<android::BufferQueueConsumer>( m_server.TryGetBinder(consumer_binder_id)); - - if (!display || !binder) { + if (!binder) { return; } auto buffer_item_consumer = std::make_shared<android::BufferItemConsumer>(std::move(binder)); buffer_item_consumer->Connect(false); - display->stack.layers.emplace_back(std::move(buffer_item_consumer), consumer_binder_id); + m_layers.layers.emplace_back( + std::make_shared<Layer>(std::move(buffer_item_consumer), consumer_binder_id)); +} + +void SurfaceFlinger::DestroyLayer(s32 consumer_binder_id) { + std::erase_if(m_layers.layers, + [&](auto& layer) { return layer->consumer_id == consumer_binder_id; }); +} + +void SurfaceFlinger::AddLayerToDisplayStack(u64 display_id, s32 consumer_binder_id) { + auto* const display = this->FindDisplay(display_id); + auto layer = this->FindLayer(consumer_binder_id); + + if (!display || !layer) { + return; + } + + display->stack.layers.emplace_back(std::move(layer)); } void SurfaceFlinger::RemoveLayerFromDisplayStack(u64 display_id, s32 consumer_binder_id) { @@ -69,18 +84,18 @@ void SurfaceFlinger::RemoveLayerFromDisplayStack(u64 display_id, s32 consumer_bi m_composer.RemoveLayerLocked(*display, consumer_binder_id); std::erase_if(display->stack.layers, - [&](auto& layer) { return layer.consumer_id == consumer_binder_id; }); + [&](auto& layer) { return layer->consumer_id == consumer_binder_id; }); } void SurfaceFlinger::SetLayerVisibility(s32 consumer_binder_id, bool visible) { - if (auto* layer = this->FindLayer(consumer_binder_id); layer != nullptr) { + if (const auto layer = this->FindLayer(consumer_binder_id); layer != nullptr) { layer->visible = visible; return; } } void SurfaceFlinger::SetLayerBlending(s32 consumer_binder_id, LayerBlending blending) { - if (auto* layer = this->FindLayer(consumer_binder_id); layer != nullptr) { + if (const auto layer = this->FindLayer(consumer_binder_id); layer != nullptr) { layer->blending = blending; return; } @@ -96,9 +111,9 @@ Display* SurfaceFlinger::FindDisplay(u64 display_id) { return nullptr; } -Layer* SurfaceFlinger::FindLayer(s32 consumer_binder_id) { - for (auto& display : m_displays) { - if (auto* layer = display.FindLayer(consumer_binder_id); layer != nullptr) { +std::shared_ptr<Layer> SurfaceFlinger::FindLayer(s32 consumer_binder_id) { + for (auto& layer : m_layers.layers) { + if (layer->consumer_id == consumer_binder_id) { return layer; } } diff --git a/src/core/hle/service/nvnflinger/surface_flinger.h b/src/core/hle/service/nvnflinger/surface_flinger.h index d8c53fbda..406281c83 100644 --- a/src/core/hle/service/nvnflinger/surface_flinger.h +++ b/src/core/hle/service/nvnflinger/surface_flinger.h @@ -36,6 +36,9 @@ public: void RemoveDisplay(u64 display_id); bool ComposeDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, u64 display_id); + void CreateLayer(s32 consumer_binder_id); + void DestroyLayer(s32 consumer_binder_id); + void AddLayerToDisplayStack(u64 display_id, s32 consumer_binder_id); void RemoveLayerFromDisplayStack(u64 display_id, s32 consumer_binder_id); @@ -44,7 +47,7 @@ public: private: Display* FindDisplay(u64 display_id); - Layer* FindLayer(s32 consumer_binder_id); + std::shared_ptr<Layer> FindLayer(s32 consumer_binder_id); public: // TODO: these don't belong here @@ -57,6 +60,7 @@ private: KernelHelpers::ServiceContext m_context; std::vector<Display> m_displays; + LayerStack m_layers; std::shared_ptr<Nvidia::Module> nvdrv; s32 disp_fd; HardwareComposer m_composer; diff --git a/src/core/hle/service/vi/container.cpp b/src/core/hle/service/vi/container.cpp index 310a207f1..9074f4ae0 100644 --- a/src/core/hle/service/vi/container.cpp +++ b/src/core/hle/service/vi/container.cpp @@ -43,11 +43,7 @@ void Container::OnTerminate() { m_is_shut_down = true; - m_layers.ForEachLayer([&](auto& layer) { - if (layer.IsOpen()) { - this->DestroyBufferQueueLocked(&layer); - } - }); + m_layers.ForEachLayer([&](auto& layer) { this->DestroyLayerLocked(layer.GetId()); }); m_displays.ForEachDisplay( [&](auto& display) { m_surface_flinger->RemoveDisplay(display.GetId()); }); @@ -161,16 +157,29 @@ Result Container::CreateLayerLocked(u64* out_layer_id, u64 display_id, u64 owner auto* const display = m_displays.GetDisplayById(display_id); R_UNLESS(display != nullptr, VI::ResultNotFound); - auto* const layer = m_layers.CreateLayer(owner_aruid, display); + s32 consumer_binder_id, producer_binder_id; + m_surface_flinger->CreateBufferQueue(&consumer_binder_id, &producer_binder_id); + + auto* const layer = + m_layers.CreateLayer(owner_aruid, display, consumer_binder_id, producer_binder_id); R_UNLESS(layer != nullptr, VI::ResultNotFound); + m_surface_flinger->CreateLayer(consumer_binder_id); + *out_layer_id = layer->GetId(); R_SUCCEED(); } Result Container::DestroyLayerLocked(u64 layer_id) { - R_SUCCEED_IF(m_layers.DestroyLayer(layer_id)); - R_THROW(VI::ResultNotFound); + auto* const layer = m_layers.GetLayerById(layer_id); + R_UNLESS(layer != nullptr, VI::ResultNotFound); + + m_surface_flinger->DestroyLayer(layer->GetConsumerBinderId()); + m_surface_flinger->DestroyBufferQueue(layer->GetConsumerBinderId(), + layer->GetProducerBinderId()); + m_layers.DestroyLayer(layer_id); + + R_SUCCEED(); } Result Container::OpenLayerLocked(s32* out_producer_binder_id, u64 layer_id, u64 aruid) { @@ -181,7 +190,12 @@ Result Container::OpenLayerLocked(s32* out_producer_binder_id, u64 layer_id, u64 R_UNLESS(!layer->IsOpen(), VI::ResultOperationFailed); R_UNLESS(layer->GetOwnerAruid() == aruid, VI::ResultPermissionDenied); - this->CreateBufferQueueLocked(layer); + layer->Open(); + + if (auto* display = layer->GetDisplay(); display != nullptr) { + m_surface_flinger->AddLayerToDisplayStack(display->GetId(), layer->GetConsumerBinderId()); + } + *out_producer_binder_id = layer->GetProducerBinderId(); R_SUCCEED(); @@ -192,30 +206,14 @@ Result Container::CloseLayerLocked(u64 layer_id) { R_UNLESS(layer != nullptr, VI::ResultNotFound); R_UNLESS(layer->IsOpen(), VI::ResultOperationFailed); - this->DestroyBufferQueueLocked(layer); - - R_SUCCEED(); -} - -void Container::CreateBufferQueueLocked(Layer* layer) { - s32 consumer_binder_id, producer_binder_id; - m_surface_flinger->CreateBufferQueue(&consumer_binder_id, &producer_binder_id); - layer->Open(consumer_binder_id, producer_binder_id); - - if (auto* display = layer->GetDisplay(); display != nullptr) { - m_surface_flinger->AddLayerToDisplayStack(display->GetId(), consumer_binder_id); - } -} - -void Container::DestroyBufferQueueLocked(Layer* layer) { if (auto* display = layer->GetDisplay(); display != nullptr) { m_surface_flinger->RemoveLayerFromDisplayStack(display->GetId(), layer->GetConsumerBinderId()); } layer->Close(); - m_surface_flinger->DestroyBufferQueue(layer->GetConsumerBinderId(), - layer->GetProducerBinderId()); + + R_SUCCEED(); } bool Container::ComposeOnDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, diff --git a/src/core/hle/service/vi/container.h b/src/core/hle/service/vi/container.h index cd0d2ca86..5eac4d77d 100644 --- a/src/core/hle/service/vi/container.h +++ b/src/core/hle/service/vi/container.h @@ -72,9 +72,6 @@ private: Result OpenLayerLocked(s32* out_producer_binder_id, u64 layer_id, u64 aruid); Result CloseLayerLocked(u64 layer_id); - void CreateBufferQueueLocked(Layer* layer); - void DestroyBufferQueueLocked(Layer* layer); - public: bool ComposeOnDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, u64 display_id); diff --git a/src/core/hle/service/vi/layer.h b/src/core/hle/service/vi/layer.h index b85c8df61..e4c9c9864 100644 --- a/src/core/hle/service/vi/layer.h +++ b/src/core/hle/service/vi/layer.h @@ -13,29 +13,31 @@ class Layer { public: constexpr Layer() = default; - void Initialize(u64 id, u64 owner_aruid, Display* display) { + void Initialize(u64 id, u64 owner_aruid, Display* display, s32 consumer_binder_id, + s32 producer_binder_id) { m_id = id; m_owner_aruid = owner_aruid; m_display = display; + m_consumer_binder_id = consumer_binder_id; + m_producer_binder_id = producer_binder_id; m_is_initialized = true; } void Finalize() { m_id = {}; + m_owner_aruid = {}; m_display = {}; + m_consumer_binder_id = {}; + m_producer_binder_id = {}; m_is_initialized = {}; } - void Open(s32 consumer_binder_id, s32 producer_binder_id) { - m_consumer_binder_id = consumer_binder_id; - m_producer_binder_id = producer_binder_id; + void Open() { m_is_open = true; } void Close() { - m_producer_binder_id = {}; - m_consumer_binder_id = {}; - m_is_open = {}; + m_is_open = false; } u64 GetId() const { diff --git a/src/core/hle/service/vi/layer_list.h b/src/core/hle/service/vi/layer_list.h index 1738ede9a..4afca6f40 100644 --- a/src/core/hle/service/vi/layer_list.h +++ b/src/core/hle/service/vi/layer_list.h @@ -11,13 +11,15 @@ class LayerList { public: constexpr LayerList() = default; - Layer* CreateLayer(u64 owner_aruid, Display* display) { + Layer* CreateLayer(u64 owner_aruid, Display* display, s32 consumer_binder_id, + s32 producer_binder_id) { Layer* const layer = GetFreeLayer(); if (!layer) { return nullptr; } - layer->Initialize(++m_next_id, owner_aruid, display); + layer->Initialize(++m_next_id, owner_aruid, display, consumer_binder_id, + producer_binder_id); return layer; } diff --git a/src/core/hle/service/vi/shared_buffer_manager.cpp b/src/core/hle/service/vi/shared_buffer_manager.cpp index 869b18961..12cba16fa 100644 --- a/src/core/hle/service/vi/shared_buffer_manager.cpp +++ b/src/core/hle/service/vi/shared_buffer_manager.cpp @@ -285,7 +285,7 @@ void SharedBufferManager::DestroySession(Kernel::KProcess* owner_process) { auto& session = it->second; // Destroy the layer. - R_ASSERT(m_container.DestroyStrayLayer(session.layer_id)); + m_container.DestroyStrayLayer(session.layer_id); // Close nvmap handle. FreeHandle(session.buffer_nvmap_handle, *m_nvdrv, session.nvmap_fd); @@ -322,8 +322,6 @@ Result SharedBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size, Result SharedBufferManager::AcquireSharedFrameBuffer(android::Fence* out_fence, std::array<s32, 4>& out_slot_indexes, s64* out_target_slot, u64 layer_id) { - std::scoped_lock lk{m_guard}; - // Get the producer. std::shared_ptr<android::BufferQueueProducer> producer; R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id)); @@ -347,8 +345,6 @@ Result SharedBufferManager::PresentSharedFrameBuffer(android::Fence fence, Common::Rectangle<s32> crop_region, u32 transform, s32 swap_interval, u64 layer_id, s64 slot) { - std::scoped_lock lk{m_guard}; - // Get the producer. std::shared_ptr<android::BufferQueueProducer> producer; R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id)); @@ -379,8 +375,6 @@ Result SharedBufferManager::PresentSharedFrameBuffer(android::Fence fence, } Result SharedBufferManager::CancelSharedFrameBuffer(u64 layer_id, s64 slot) { - std::scoped_lock lk{m_guard}; - // Get the producer. std::shared_ptr<android::BufferQueueProducer> producer; R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id)); @@ -394,8 +388,6 @@ Result SharedBufferManager::CancelSharedFrameBuffer(u64 layer_id, s64 slot) { Result SharedBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, u64 layer_id) { - std::scoped_lock lk{m_guard}; - // Get the producer. std::shared_ptr<android::BufferQueueProducer> producer; R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id)); diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp index 0031fa5fb..3f9698d6b 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp @@ -261,7 +261,9 @@ void DefineEntryPoint(const IR::Program& program, EmitContext& ctx, Id main) { case Stage::Geometry: execution_model = spv::ExecutionModel::Geometry; ctx.AddCapability(spv::Capability::Geometry); - ctx.AddCapability(spv::Capability::GeometryStreams); + if (ctx.profile.support_geometry_streams) { + ctx.AddCapability(spv::Capability::GeometryStreams); + } switch (ctx.runtime_info.input_topology) { case InputTopology::Points: ctx.AddExecutionMode(main, spv::ExecutionMode::InputPoints); diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp index 9f7b6bb4b..f60da758e 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp @@ -129,7 +129,9 @@ void EmitEmitVertex(EmitContext& ctx, const IR::Value& stream) { if (ctx.runtime_info.convert_depth_mode && !ctx.profile.support_native_ndc) { ConvertDepthMode(ctx); } - if (stream.IsImmediate()) { + if (!ctx.profile.support_geometry_streams) { + throw NotImplementedException("Geometry streams"); + } else if (stream.IsImmediate()) { ctx.OpEmitStreamVertex(ctx.Def(stream)); } else { LOG_WARNING(Shader_SPIRV, "Stream is not immediate"); @@ -140,7 +142,9 @@ void EmitEmitVertex(EmitContext& ctx, const IR::Value& stream) { } void EmitEndPrimitive(EmitContext& ctx, const IR::Value& stream) { - if (stream.IsImmediate()) { + if (!ctx.profile.support_geometry_streams) { + throw NotImplementedException("Geometry streams"); + } else if (stream.IsImmediate()) { ctx.OpEndStreamPrimitive(ctx.Def(stream)); } else { LOG_WARNING(Shader_SPIRV, "Stream is not immediate"); diff --git a/src/shader_recompiler/profile.h b/src/shader_recompiler/profile.h index 7578d41cc..90e46bb1b 100644 --- a/src/shader_recompiler/profile.h +++ b/src/shader_recompiler/profile.h @@ -44,6 +44,7 @@ struct Profile { bool support_gl_derivative_control{}; bool support_scaled_attributes{}; bool support_multi_viewport{}; + bool support_geometry_streams{}; bool warp_size_potentially_larger_than_guest{}; diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index 296c90e85..ed7a5b27e 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h @@ -35,7 +35,7 @@ BufferCache<P>::BufferCache(Tegra::MaxwellDeviceMemoryManager& device_memory_, R const s64 min_spacing_critical = device_local_memory - 512_MiB; const s64 mem_threshold = std::min(device_local_memory, TARGET_THRESHOLD); const s64 min_vacancy_expected = (6 * mem_threshold) / 10; - const s64 min_vacancy_critical = (3 * mem_threshold) / 10; + const s64 min_vacancy_critical = (2 * mem_threshold) / 10; minimum_memory = static_cast<u64>( std::max(std::min(device_local_memory - min_vacancy_expected, min_spacing_expected), DEFAULT_EXPECTED_MEMORY)); diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 20f7a9702..d34b585d6 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -352,6 +352,7 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_, .support_native_ndc = device.IsExtDepthClipControlSupported(), .support_scaled_attributes = !device.MustEmulateScaledFormats(), .support_multi_viewport = device.SupportsMultiViewport(), + .support_geometry_streams = device.AreTransformFeedbackGeometryStreamsSupported(), .warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(), diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp index 5b3c7aa5a..9055b1b92 100644 --- a/src/video_core/surface.cpp +++ b/src/video_core/surface.cpp @@ -3,6 +3,7 @@ #include "common/common_types.h" #include "common/math_util.h" +#include "common/settings.h" #include "video_core/surface.h" namespace VideoCore::Surface { @@ -400,11 +401,20 @@ std::pair<u32, u32> GetASTCBlockSize(PixelFormat format) { return {DefaultBlockWidth(format), DefaultBlockHeight(format)}; } -u64 EstimatedDecompressedSize(u64 base_size, PixelFormat format) { +u64 TranscodedAstcSize(u64 base_size, PixelFormat format) { constexpr u64 RGBA8_PIXEL_SIZE = 4; const u64 base_block_size = static_cast<u64>(DefaultBlockWidth(format)) * static_cast<u64>(DefaultBlockHeight(format)) * RGBA8_PIXEL_SIZE; - return (base_size * base_block_size) / BytesPerBlock(format); + const u64 uncompressed_size = (base_size * base_block_size) / BytesPerBlock(format); + + switch (Settings::values.astc_recompression.GetValue()) { + case Settings::AstcRecompression::Bc1: + return uncompressed_size / 8; + case Settings::AstcRecompression::Bc3: + return uncompressed_size / 4; + default: + return uncompressed_size; + } } } // namespace VideoCore::Surface diff --git a/src/video_core/surface.h b/src/video_core/surface.h index a5e8e2f62..ec9cd2fbf 100644 --- a/src/video_core/surface.h +++ b/src/video_core/surface.h @@ -517,6 +517,6 @@ size_t PixelComponentSizeBitsInteger(PixelFormat format); std::pair<u32, u32> GetASTCBlockSize(PixelFormat format); -u64 EstimatedDecompressedSize(u64 base_size, PixelFormat format); +u64 TranscodedAstcSize(u64 base_size, PixelFormat format); } // namespace VideoCore::Surface diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 01c3561c9..53b4876f2 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -55,7 +55,7 @@ TextureCache<P>::TextureCache(Runtime& runtime_, Tegra::MaxwellDeviceMemoryManag const s64 min_spacing_critical = device_local_memory - 512_MiB; const s64 mem_threshold = std::min(device_local_memory, TARGET_THRESHOLD); const s64 min_vacancy_expected = (6 * mem_threshold) / 10; - const s64 min_vacancy_critical = (3 * mem_threshold) / 10; + const s64 min_vacancy_critical = (2 * mem_threshold) / 10; expected_memory = static_cast<u64>( std::max(std::min(device_local_memory - min_vacancy_expected, min_spacing_expected), DEFAULT_EXPECTED_MEMORY)); @@ -1979,7 +1979,7 @@ void TextureCache<P>::RegisterImage(ImageId image_id) { if ((IsPixelFormatASTC(image.info.format) && True(image.flags & ImageFlagBits::AcceleratedUpload)) || True(image.flags & ImageFlagBits::Converted)) { - tentative_size = EstimatedDecompressedSize(tentative_size, image.info.format); + tentative_size = TranscodedAstcSize(tentative_size, image.info.format); } total_used_memory += Common::AlignUp(tentative_size, 1024); image.lru_index = lru_cache.Insert(image_id, frame_tick); @@ -2149,7 +2149,7 @@ void TextureCache<P>::DeleteImage(ImageId image_id, bool immediate_delete) { if ((IsPixelFormatASTC(image.info.format) && True(image.flags & ImageFlagBits::AcceleratedUpload)) || True(image.flags & ImageFlagBits::Converted)) { - tentative_size = EstimatedDecompressedSize(tentative_size, image.info.format); + tentative_size = TranscodedAstcSize(tentative_size, image.info.format); } total_used_memory -= Common::AlignUp(tentative_size, 1024); const GPUVAddr gpu_addr = image.gpu_addr; diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index d7216d349..b94924a58 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -1297,10 +1297,6 @@ u64 Device::GetDeviceMemoryUsage() const { } void Device::CollectPhysicalMemoryInfo() { - // Account for resolution scaling in memory limits - const size_t normal_memory = 6_GiB; - const size_t scaler_memory = 1_GiB * Settings::values.resolution_info.ScaleUp(1); - // Calculate limits using memory budget VkPhysicalDeviceMemoryBudgetPropertiesEXT budget{}; budget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT; @@ -1331,7 +1327,15 @@ void Device::CollectPhysicalMemoryInfo() { if (!is_integrated) { const u64 reserve_memory = std::min<u64>(device_access_memory / 8, 1_GiB); device_access_memory -= reserve_memory; - device_access_memory = std::min<u64>(device_access_memory, normal_memory + scaler_memory); + + if (Settings::values.vram_usage_mode.GetValue() != Settings::VramUsageMode::Aggressive) { + // Account for resolution scaling in memory limits + const size_t normal_memory = 6_GiB; + const size_t scaler_memory = 1_GiB * Settings::values.resolution_info.ScaleUp(1); + device_access_memory = + std::min<u64>(device_access_memory, normal_memory + scaler_memory); + } + return; } const s64 available_memory = static_cast<s64>(device_access_memory - device_initial_usage); diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index a2ec26697..e3abe8ddf 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -499,6 +499,11 @@ public: return extensions.transform_feedback; } + /// Returns true if the device supports VK_EXT_transform_feedback properly. + bool AreTransformFeedbackGeometryStreamsSupported() const { + return features.transform_feedback.geometryStreams; + } + /// Returns true if the device supports VK_EXT_custom_border_color. bool IsExtCustomBorderColorSupported() const { return extensions.custom_border_color; diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/yuzu/configuration/shared_translation.cpp index d138b53c8..0549e8ae4 100644 --- a/src/yuzu/configuration/shared_translation.cpp +++ b/src/yuzu/configuration/shared_translation.cpp @@ -164,6 +164,11 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) { "the emulator to decompress to an intermediate format any card supports, RGBA8.\n" "This option recompresses RGBA8 to either the BC1 or BC3 format, saving VRAM but " "negatively affecting image quality.")); + INSERT(Settings, vram_usage_mode, tr("VRAM Usage Mode:"), + tr("Selects whether the emulator should prefer to conserve memory or make maximum usage " + "of available video memory for performance. Has no effect on integrated graphics. " + "Aggressive mode may severely impact the performance of other applications such as " + "recording software.")); INSERT( Settings, vsync_mode, tr("VSync Mode:"), tr("FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen " @@ -315,6 +320,11 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent) { PAIR(AstcRecompression, Bc1, tr("BC1 (Low quality)")), PAIR(AstcRecompression, Bc3, tr("BC3 (Medium quality)")), }}); + translations->insert({Settings::EnumMetadata<Settings::VramUsageMode>::Index(), + { + PAIR(VramUsageMode, Conservative, tr("Conservative")), + PAIR(VramUsageMode, Aggressive, tr("Aggressive")), + }}); translations->insert({Settings::EnumMetadata<Settings::RendererBackend>::Index(), { #ifdef HAS_OPENGL diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 236642fb9..b2ae3db52 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1604,6 +1604,7 @@ void GMainWindow::ConnectMenuEvents() { connect_menu(ui->action_Open_yuzu_Folder, &GMainWindow::OnOpenYuzuFolder); connect_menu(ui->action_Verify_installed_contents, &GMainWindow::OnVerifyInstalledContents); connect_menu(ui->action_Install_Firmware, &GMainWindow::OnInstallFirmware); + connect_menu(ui->action_Install_Keys, &GMainWindow::OnInstallDecryptionKeys); connect_menu(ui->action_About, &GMainWindow::OnAbout); } @@ -1633,6 +1634,7 @@ void GMainWindow::UpdateMenuState() { } ui->action_Install_Firmware->setEnabled(!emulation_running); + ui->action_Install_Keys->setEnabled(!emulation_running); for (QAction* action : applet_actions) { action->setEnabled(is_firmware_available && !emulation_running); @@ -4169,9 +4171,8 @@ void GMainWindow::OnInstallFirmware() { return; } - QString firmware_source_location = - QFileDialog::getExistingDirectory(this, tr("Select Dumped Firmware Source Location"), - QString::fromStdString(""), QFileDialog::ShowDirsOnly); + const QString firmware_source_location = QFileDialog::getExistingDirectory( + this, tr("Select Dumped Firmware Source Location"), {}, QFileDialog::ShowDirsOnly); if (firmware_source_location.isEmpty()) { return; } @@ -4202,8 +4203,9 @@ void GMainWindow::OnInstallFirmware() { std::vector<std::filesystem::path> out; const Common::FS::DirEntryCallable callback = [&out](const std::filesystem::directory_entry& entry) { - if (entry.path().has_extension() && entry.path().extension() == ".nca") + if (entry.path().has_extension() && entry.path().extension() == ".nca") { out.emplace_back(entry.path()); + } return true; }; @@ -4235,7 +4237,6 @@ void GMainWindow::OnInstallFirmware() { auto firmware_vdir = sysnand_content_vdir->GetDirectoryRelative("registered"); bool success = true; - bool cancelled = false; int i = 0; for (const auto& firmware_src_path : out) { i++; @@ -4250,24 +4251,22 @@ void GMainWindow::OnInstallFirmware() { success = false; } - if (QtProgressCallback(100, 20 + (int)(((float)(i) / (float)out.size()) * 70.0))) { - success = false; - cancelled = true; - break; + if (QtProgressCallback( + 100, 20 + static_cast<int>(((i) / static_cast<float>(out.size())) * 70.0))) { + progress.close(); + QMessageBox::warning( + this, tr("Firmware install failed"), + tr("Firmware installation cancelled, firmware may be in bad state, " + "restart yuzu or re-install firmware.")); + return; } } - if (!success && !cancelled) { + if (!success) { progress.close(); QMessageBox::critical(this, tr("Firmware install failed"), tr("One or more firmware files failed to copy into NAND.")); return; - } else if (cancelled) { - progress.close(); - QMessageBox::warning(this, tr("Firmware install failed"), - tr("Firmware installation cancelled, firmware may be in bad state, " - "restart yuzu or re-install firmware.")); - return; } // Re-scan VFS for the newly placed firmware files. @@ -4295,6 +4294,84 @@ void GMainWindow::OnInstallFirmware() { OnCheckFirmwareDecryption(); } +void GMainWindow::OnInstallDecryptionKeys() { + // Don't do this while emulation is running. + if (emu_thread != nullptr && emu_thread->IsRunning()) { + return; + } + + const QString key_source_location = QFileDialog::getOpenFileName( + this, tr("Select Dumped Keys Location"), {}, QStringLiteral("prod.keys (prod.keys)"), {}, + QFileDialog::ReadOnly); + if (key_source_location.isEmpty()) { + return; + } + + // Verify that it contains prod.keys, title.keys and optionally, key_retail.bin + LOG_INFO(Frontend, "Installing key files from {}", key_source_location.toStdString()); + + const std::filesystem::path prod_key_path = key_source_location.toStdString(); + const std::filesystem::path key_source_path = prod_key_path.parent_path(); + if (!Common::FS::IsDir(key_source_path)) { + return; + } + + bool prod_keys_found = false; + std::vector<std::filesystem::path> source_key_files; + + if (Common::FS::Exists(prod_key_path)) { + prod_keys_found = true; + source_key_files.emplace_back(prod_key_path); + } + + if (Common::FS::Exists(key_source_path / "title.keys")) { + source_key_files.emplace_back(key_source_path / "title.keys"); + } + + if (Common::FS::Exists(key_source_path / "key_retail.bin")) { + source_key_files.emplace_back(key_source_path / "key_retail.bin"); + } + + // There should be at least prod.keys. + if (source_key_files.empty() || !prod_keys_found) { + QMessageBox::warning(this, tr("Decryption Keys install failed"), + tr("prod.keys is a required decryption key file.")); + return; + } + + const auto yuzu_keys_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::KeysDir); + for (auto key_file : source_key_files) { + std::filesystem::path destination_key_file = yuzu_keys_dir / key_file.filename(); + if (!std::filesystem::copy_file(key_file, destination_key_file, + std::filesystem::copy_options::overwrite_existing)) { + LOG_ERROR(Frontend, "Failed to copy file {} to {}", key_file.string(), + destination_key_file.string()); + QMessageBox::critical(this, tr("Decryption Keys install failed"), + tr("One or more keys failed to copy.")); + return; + } + } + + // Reinitialize the key manager, re-read the vfs (for update/dlc files), + // and re-populate the game list in the UI if the user has already added + // game folders. + Core::Crypto::KeyManager::Instance().ReloadKeys(); + system->GetFileSystemController().CreateFactories(*vfs); + game_list->PopulateAsync(UISettings::values.game_dirs); + + if (ContentManager::AreKeysPresent()) { + QMessageBox::information(this, tr("Decryption Keys install succeeded"), + tr("Decryption Keys were successfully installed")); + } else { + QMessageBox::critical( + this, tr("Decryption Keys install failed"), + tr("Decryption Keys failed to initialize. Check that your dumping tools are " + "up to date and re-dump keys.")); + } + + OnCheckFirmwareDecryption(); +} + void GMainWindow::OnAbout() { AboutDialog aboutDialog(this); aboutDialog.exec(); diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 1f0e35c67..fce643f3f 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -381,6 +381,7 @@ private slots: void OnOpenYuzuFolder(); void OnVerifyInstalledContents(); void OnInstallFirmware(); + void OnInstallDecryptionKeys(); void OnAbout(); void OnToggleFilterBar(); void OnToggleStatusBar(); diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui index 6ff444a22..85dc1f2f6 100644 --- a/src/yuzu/main.ui +++ b/src/yuzu/main.ui @@ -165,8 +165,9 @@ <addaction name="separator"/> <addaction name="action_Configure_Tas"/> </widget> - <addaction name="action_Verify_installed_contents"/> + <addaction name="action_Install_Keys"/> <addaction name="action_Install_Firmware"/> + <addaction name="action_Verify_installed_contents"/> <addaction name="separator"/> <addaction name="menu_cabinet_applet"/> <addaction name="action_Load_Album"/> @@ -469,6 +470,11 @@ <string>Install Firmware</string> </property> </action> + <action name="action_Install_Keys"> + <property name="text"> + <string>Install Decryption Keys</string> + </property> + </action> </widget> <resources> <include location="yuzu.qrc"/> |