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"/>  | 
