Compare commits
72 Commits
android-25
...
android-26
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f44933930d | ||
|
|
e96826419b | ||
|
|
3f232161be | ||
|
|
98eb3df15c | ||
|
|
74ba9dde58 | ||
|
|
f3f63aa1e7 | ||
|
|
1bea1ee418 | ||
|
|
8bbc209950 | ||
|
|
9e1a67b950 | ||
|
|
de5422b1fd | ||
|
|
45f450fca5 | ||
|
|
9a3fd76b25 | ||
|
|
60fc6df407 | ||
|
|
de2d496e71 | ||
|
|
7b5bdd076d | ||
|
|
e0c17a2113 | ||
|
|
b107435a3f | ||
|
|
4e1fcd4a63 | ||
|
|
ea4a96b45e | ||
|
|
6a90db8c19 | ||
|
|
0e5972b0b5 | ||
|
|
5f7608a7c6 | ||
|
|
668ff0db3a | ||
|
|
9f159dd62c | ||
|
|
d1eaeeed8c | ||
|
|
10e27a2902 | ||
|
|
f567a41f53 | ||
|
|
704c62ca01 | ||
|
|
8d5473e67c | ||
|
|
3b1b98c645 | ||
|
|
daf350f5d3 | ||
|
|
c9ef2e26ca | ||
|
|
310c1f50be | ||
|
|
665fce871f | ||
|
|
58c7e846cb | ||
|
|
8b0fb98a11 | ||
|
|
8615509c40 | ||
|
|
d0af52f28e | ||
|
|
d45a12826c | ||
|
|
940a71422e | ||
|
|
4cdf18095d | ||
|
|
2d43831d1f | ||
|
|
2e96921f9c | ||
|
|
cf0de18982 | ||
|
|
ae83ee28a3 | ||
|
|
306ed4984b | ||
|
|
626f2e65b1 | ||
|
|
2eded86b4b | ||
|
|
786fc512e2 | ||
|
|
c31ac45332 | ||
|
|
db172ba249 | ||
|
|
bb59940b03 | ||
|
|
04887953ff | ||
|
|
8ea72cc99d | ||
|
|
44d2e90217 | ||
|
|
12926eb5db | ||
|
|
ae114d2fa1 | ||
|
|
270d07be2f | ||
|
|
947cdbe4b1 | ||
|
|
a07f0883b9 | ||
|
|
812f23d05c | ||
|
|
dcce9837d2 | ||
|
|
ee8eccc5fa | ||
|
|
7b79cddacd | ||
|
|
110969e207 | ||
|
|
9c0724b270 | ||
|
|
462ea921e3 | ||
|
|
cb29aa0473 | ||
|
|
3067bfd126 | ||
|
|
368bf2211f | ||
|
|
de8a623932 | ||
|
|
865a0186b6 |
14
README.md
14
README.md
@@ -1,3 +1,17 @@
|
||||
| Pull Request | Commit | Title | Author | Merged? |
|
||||
|----|----|----|----|----|
|
||||
| [12461](https://github.com/yuzu-emu/yuzu//pull/12461) | [`2831f5dc6`](https://github.com/yuzu-emu/yuzu//pull/12461/files) | Rework Nvdec and VIC to fix out-of-order videos, and speed up decoding. | [Kelebek1](https://github.com/Kelebek1/) | Yes |
|
||||
| [12749](https://github.com/yuzu-emu/yuzu//pull/12749) | [`aad4b0d6f`](https://github.com/yuzu-emu/yuzu//pull/12749/files) | general: workarounds for SMMU syncing issues | [liamwhite](https://github.com/liamwhite/) | Yes |
|
||||
| [12982](https://github.com/yuzu-emu/yuzu//pull/12982) | [`ef5027712`](https://github.com/yuzu-emu/yuzu//pull/12982/files) | fs: Add FileSystemAccessor and use cmif serialization | [FearlessTobi](https://github.com/FearlessTobi/) | Yes |
|
||||
| [13000](https://github.com/yuzu-emu/yuzu//pull/13000) | [`461eaca7e`](https://github.com/yuzu-emu/yuzu//pull/13000/files) | device_memory_manager: skip unregistered interfaces on invalidate | [liamwhite](https://github.com/liamwhite/) | Yes |
|
||||
| [13075](https://github.com/yuzu-emu/yuzu//pull/13075) | [`f46dc3168`](https://github.com/yuzu-emu/yuzu//pull/13075/files) | shader_recompiler: throw on missing geometry streams in geometry shaders | [liamwhite](https://github.com/liamwhite/) | Yes |
|
||||
| [13096](https://github.com/yuzu-emu/yuzu//pull/13096) | [`0a8759057`](https://github.com/yuzu-emu/yuzu//pull/13096/files) | texture_cache: use two-pass collection for costly load resources | [liamwhite](https://github.com/liamwhite/) | Yes |
|
||||
|
||||
|
||||
End of merge log. You can find the original README.md below the break.
|
||||
|
||||
-----
|
||||
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2018 yuzu Emulator Project
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
7
externals/CMakeLists.txt
vendored
7
externals/CMakeLists.txt
vendored
@@ -314,3 +314,10 @@ endif()
|
||||
if (NOT TARGET SimpleIni::SimpleIni)
|
||||
add_subdirectory(simpleini)
|
||||
endif()
|
||||
|
||||
# sse2neon
|
||||
if (ARCHITECTURE_arm64 AND NOT TARGET sse2neon)
|
||||
add_library(sse2neon INTERFACE)
|
||||
target_include_directories(sse2neon INTERFACE sse2neon)
|
||||
endif()
|
||||
|
||||
|
||||
9282
externals/sse2neon/sse2neon.h
vendored
Normal file
9282
externals/sse2neon/sse2neon.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -164,6 +164,7 @@ else()
|
||||
|
||||
if (MINGW)
|
||||
add_definitions(-DMINGW_HAS_SECURE_API)
|
||||
add_compile_options("-msse4.1")
|
||||
|
||||
if (MINGW_STATIC_BUILD)
|
||||
add_definitions(-DQT_STATICPLUGIN)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -810,7 +810,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
}
|
||||
}
|
||||
}
|
||||
binding.doneControlConfig.setVisible(false)
|
||||
binding.doneControlConfig.setVisible(true)
|
||||
binding.surfaceInputOverlay.setIsInEditMode(true)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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();
|
||||
@@ -404,7 +407,9 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath,
|
||||
const size_t program_index,
|
||||
const bool frontend_initiated) {
|
||||
MicroProfileOnThreadCreate("EmuThread");
|
||||
SCOPE_EXIT({ MicroProfileShutdown(); });
|
||||
SCOPE_EXIT {
|
||||
MicroProfileShutdown();
|
||||
};
|
||||
|
||||
LOG_INFO(Frontend, "starting");
|
||||
|
||||
@@ -413,7 +418,9 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath,
|
||||
return Core::SystemResultStatus::ErrorLoader;
|
||||
}
|
||||
|
||||
SCOPE_EXIT({ EmulationSession::GetInstance().ShutdownEmulation(); });
|
||||
SCOPE_EXIT {
|
||||
EmulationSession::GetInstance().ShutdownEmulation();
|
||||
};
|
||||
|
||||
jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath, program_index,
|
||||
frontend_initiated);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -357,7 +357,9 @@ bool IsCubebSuitable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
SCOPE_EXIT({ cubeb_destroy(ctx); });
|
||||
SCOPE_EXIT {
|
||||
cubeb_destroy(ctx);
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
if (SUCCEEDED(com_init_result)) {
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
namespace AudioCore::Sink {
|
||||
|
||||
void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) {
|
||||
SCOPE_EXIT({
|
||||
SCOPE_EXIT {
|
||||
queue.enqueue(buffer);
|
||||
++queued_buffers;
|
||||
});
|
||||
};
|
||||
|
||||
if (type == StreamType::In) {
|
||||
return;
|
||||
|
||||
@@ -20,7 +20,9 @@ std::string DemangleSymbol(const std::string& mangled) {
|
||||
}
|
||||
|
||||
char* demangled = nullptr;
|
||||
SCOPE_EXIT({ std::free(demangled); });
|
||||
SCOPE_EXIT {
|
||||
std::free(demangled);
|
||||
};
|
||||
|
||||
if (is_itanium(mangled)) {
|
||||
demangled = llvm::itaniumDemangle(mangled.c_str());
|
||||
|
||||
@@ -430,11 +430,11 @@ public:
|
||||
explicit Impl(size_t backing_size_, size_t virtual_size_)
|
||||
: backing_size{backing_size_}, virtual_size{virtual_size_} {
|
||||
bool good = false;
|
||||
SCOPE_EXIT({
|
||||
SCOPE_EXIT {
|
||||
if (!good) {
|
||||
Release();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
long page_size = sysconf(_SC_PAGESIZE);
|
||||
if (page_size != 0x1000) {
|
||||
|
||||
@@ -24,10 +24,10 @@ bool PageTable::ContinueTraversal(TraversalEntry* out_entry, TraversalContext* c
|
||||
out_entry->block_size = page_size;
|
||||
|
||||
// Regardless of whether the page was mapped, advance on exit.
|
||||
SCOPE_EXIT({
|
||||
SCOPE_EXIT {
|
||||
context->next_page += 1;
|
||||
context->next_offset += page_size;
|
||||
});
|
||||
};
|
||||
|
||||
// Validate that we can read the actual entry.
|
||||
const auto page = context->next_page;
|
||||
|
||||
@@ -7,29 +7,61 @@
|
||||
#include "common/common_funcs.h"
|
||||
|
||||
namespace detail {
|
||||
template <typename Func>
|
||||
struct ScopeExitHelper {
|
||||
explicit ScopeExitHelper(Func&& func_) : func(std::move(func_)) {}
|
||||
~ScopeExitHelper() {
|
||||
template <class F>
|
||||
class ScopeGuard {
|
||||
YUZU_NON_COPYABLE(ScopeGuard);
|
||||
|
||||
private:
|
||||
F f;
|
||||
bool active;
|
||||
|
||||
public:
|
||||
constexpr ScopeGuard(F f_) : f(std::move(f_)), active(true) {}
|
||||
constexpr ~ScopeGuard() {
|
||||
if (active) {
|
||||
func();
|
||||
f();
|
||||
}
|
||||
}
|
||||
|
||||
void Cancel() {
|
||||
constexpr void Cancel() {
|
||||
active = false;
|
||||
}
|
||||
|
||||
Func func;
|
||||
bool active{true};
|
||||
constexpr ScopeGuard(ScopeGuard&& rhs) : f(std::move(rhs.f)), active(rhs.active) {
|
||||
rhs.Cancel();
|
||||
}
|
||||
|
||||
ScopeGuard& operator=(ScopeGuard&& rhs) = delete;
|
||||
};
|
||||
|
||||
template <typename Func>
|
||||
ScopeExitHelper<Func> ScopeExit(Func&& func) {
|
||||
return ScopeExitHelper<Func>(std::forward<Func>(func));
|
||||
template <class F>
|
||||
constexpr ScopeGuard<F> MakeScopeGuard(F f) {
|
||||
return ScopeGuard<F>(std::move(f));
|
||||
}
|
||||
|
||||
enum class ScopeGuardOnExit {};
|
||||
|
||||
template <typename F>
|
||||
constexpr ScopeGuard<F> operator+(ScopeGuardOnExit, F&& f) {
|
||||
return ScopeGuard<F>(std::forward<F>(f));
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
#define CONCATENATE_IMPL(s1, s2) s1##s2
|
||||
#define CONCATENATE(s1, s2) CONCATENATE_IMPL(s1, s2)
|
||||
|
||||
#ifdef __COUNTER__
|
||||
#define ANONYMOUS_VARIABLE(pref) CONCATENATE(pref, __COUNTER__)
|
||||
#else
|
||||
#define ANONYMOUS_VARIABLE(pref) CONCATENATE(pref, __LINE__)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This macro is similar to SCOPE_EXIT, except the object is caller managed. This is intended to be
|
||||
* used when the caller might want to cancel the ScopeExit.
|
||||
*/
|
||||
#define SCOPE_GUARD detail::ScopeGuardOnExit() + [&]()
|
||||
|
||||
/**
|
||||
* This macro allows you to conveniently specify a block of code that will run on scope exit. Handy
|
||||
* for doing ad-hoc clean-up tasks in a function with multiple returns.
|
||||
@@ -38,7 +70,7 @@ ScopeExitHelper<Func> ScopeExit(Func&& func) {
|
||||
* \code
|
||||
* const int saved_val = g_foo;
|
||||
* g_foo = 55;
|
||||
* SCOPE_EXIT({ g_foo = saved_val; });
|
||||
* SCOPE_EXIT{ g_foo = saved_val; };
|
||||
*
|
||||
* if (Bar()) {
|
||||
* return 0;
|
||||
@@ -47,10 +79,4 @@ ScopeExitHelper<Func> ScopeExit(Func&& func) {
|
||||
* }
|
||||
* \endcode
|
||||
*/
|
||||
#define SCOPE_EXIT(body) auto CONCAT2(scope_exit_helper_, __LINE__) = detail::ScopeExit([&]() body)
|
||||
|
||||
/**
|
||||
* This macro is similar to SCOPE_EXIT, except the object is caller managed. This is intended to be
|
||||
* used when the caller might want to cancel the ScopeExit.
|
||||
*/
|
||||
#define SCOPE_GUARD(body) detail::ScopeExit([&]() body)
|
||||
#define SCOPE_EXIT auto ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE_) = SCOPE_GUARD
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
add_library(core STATIC
|
||||
arm/arm_interface.h
|
||||
arm/arm_interface.cpp
|
||||
arm/arm_interface.h
|
||||
arm/debug.cpp
|
||||
arm/debug.h
|
||||
arm/exclusive_monitor.cpp
|
||||
@@ -37,10 +37,10 @@ add_library(core STATIC
|
||||
debugger/gdbstub.h
|
||||
debugger/gdbstub_arch.cpp
|
||||
debugger/gdbstub_arch.h
|
||||
device_memory_manager.h
|
||||
device_memory_manager.inc
|
||||
device_memory.cpp
|
||||
device_memory.h
|
||||
device_memory_manager.h
|
||||
device_memory_manager.inc
|
||||
file_sys/bis_factory.cpp
|
||||
file_sys/bis_factory.h
|
||||
file_sys/card_image.cpp
|
||||
@@ -59,8 +59,12 @@ add_library(core STATIC
|
||||
file_sys/fs_path.h
|
||||
file_sys/fs_path_utility.h
|
||||
file_sys/fs_string_util.h
|
||||
file_sys/fsa/fs_i_directory.h
|
||||
file_sys/fsa/fs_i_file.h
|
||||
file_sys/fsa/fs_i_filesystem.h
|
||||
file_sys/fsmitm_romfsbuild.cpp
|
||||
file_sys/fsmitm_romfsbuild.h
|
||||
file_sys/fssrv/fssrv_sf_path.h
|
||||
file_sys/fssystem/fs_i_storage.h
|
||||
file_sys/fssystem/fs_types.h
|
||||
file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.cpp
|
||||
@@ -390,6 +394,20 @@ add_library(core STATIC
|
||||
hle/service/acc/errors.h
|
||||
hle/service/acc/profile_manager.cpp
|
||||
hle/service/acc/profile_manager.h
|
||||
hle/service/am/am.cpp
|
||||
hle/service/am/am.h
|
||||
hle/service/am/am_results.h
|
||||
hle/service/am/am_types.h
|
||||
hle/service/am/applet.cpp
|
||||
hle/service/am/applet.h
|
||||
hle/service/am/applet_data_broker.cpp
|
||||
hle/service/am/applet_data_broker.h
|
||||
hle/service/am/applet_manager.cpp
|
||||
hle/service/am/applet_manager.h
|
||||
hle/service/am/applet_message_queue.cpp
|
||||
hle/service/am/applet_message_queue.h
|
||||
hle/service/am/display_layer_manager.cpp
|
||||
hle/service/am/display_layer_manager.h
|
||||
hle/service/am/frontend/applet_cabinet.cpp
|
||||
hle/service/am/frontend/applet_cabinet.h
|
||||
hle/service/am/frontend/applet_controller.cpp
|
||||
@@ -411,24 +429,10 @@ add_library(core STATIC
|
||||
hle/service/am/frontend/applet_web_browser_types.h
|
||||
hle/service/am/frontend/applets.cpp
|
||||
hle/service/am/frontend/applets.h
|
||||
hle/service/am/am.cpp
|
||||
hle/service/am/am.h
|
||||
hle/service/am/am_results.h
|
||||
hle/service/am/am_types.h
|
||||
hle/service/am/applet.cpp
|
||||
hle/service/am/applet.h
|
||||
hle/service/am/applet_manager.cpp
|
||||
hle/service/am/applet_data_broker.cpp
|
||||
hle/service/am/applet_data_broker.h
|
||||
hle/service/am/applet_manager.h
|
||||
hle/service/am/applet_message_queue.cpp
|
||||
hle/service/am/applet_message_queue.h
|
||||
hle/service/am/hid_registration.cpp
|
||||
hle/service/am/hid_registration.h
|
||||
hle/service/am/library_applet_storage.cpp
|
||||
hle/service/am/library_applet_storage.h
|
||||
hle/service/am/managed_layer_holder.cpp
|
||||
hle/service/am/managed_layer_holder.h
|
||||
hle/service/am/process.cpp
|
||||
hle/service/am/process.h
|
||||
hle/service/am/service/all_system_applet_proxies_service.cpp
|
||||
@@ -441,10 +445,10 @@ add_library(core STATIC
|
||||
hle/service/am/service/application_creator.h
|
||||
hle/service/am/service/application_functions.cpp
|
||||
hle/service/am/service/application_functions.h
|
||||
hle/service/am/service/application_proxy_service.cpp
|
||||
hle/service/am/service/application_proxy_service.h
|
||||
hle/service/am/service/application_proxy.cpp
|
||||
hle/service/am/service/application_proxy.h
|
||||
hle/service/am/service/application_proxy_service.cpp
|
||||
hle/service/am/service/application_proxy_service.h
|
||||
hle/service/am/service/audio_controller.cpp
|
||||
hle/service/am/service/audio_controller.h
|
||||
hle/service/am/service/common_state_getter.cpp
|
||||
@@ -473,16 +477,14 @@ add_library(core STATIC
|
||||
hle/service/am/service/process_winding_controller.h
|
||||
hle/service/am/service/self_controller.cpp
|
||||
hle/service/am/service/self_controller.h
|
||||
hle/service/am/service/storage_accessor.cpp
|
||||
hle/service/am/service/storage_accessor.h
|
||||
hle/service/am/service/storage.cpp
|
||||
hle/service/am/service/storage.h
|
||||
hle/service/am/service/storage_accessor.cpp
|
||||
hle/service/am/service/storage_accessor.h
|
||||
hle/service/am/service/system_applet_proxy.cpp
|
||||
hle/service/am/service/system_applet_proxy.h
|
||||
hle/service/am/service/window_controller.cpp
|
||||
hle/service/am/service/window_controller.h
|
||||
hle/service/am/system_buffer_manager.cpp
|
||||
hle/service/am/system_buffer_manager.h
|
||||
hle/service/aoc/aoc_u.cpp
|
||||
hle/service/aoc/aoc_u.h
|
||||
hle/service/apm/apm.cpp
|
||||
@@ -510,18 +512,6 @@ add_library(core STATIC
|
||||
hle/service/audio/hwopus.h
|
||||
hle/service/bcat/backend/backend.cpp
|
||||
hle/service/bcat/backend/backend.h
|
||||
hle/service/bcat/news/newly_arrived_event_holder.cpp
|
||||
hle/service/bcat/news/newly_arrived_event_holder.h
|
||||
hle/service/bcat/news/news_data_service.cpp
|
||||
hle/service/bcat/news/news_data_service.h
|
||||
hle/service/bcat/news/news_database_service.cpp
|
||||
hle/service/bcat/news/news_database_service.h
|
||||
hle/service/bcat/news/news_service.cpp
|
||||
hle/service/bcat/news/news_service.h
|
||||
hle/service/bcat/news/overwrite_event_holder.cpp
|
||||
hle/service/bcat/news/overwrite_event_holder.h
|
||||
hle/service/bcat/news/service_creator.cpp
|
||||
hle/service/bcat/news/service_creator.h
|
||||
hle/service/bcat/bcat.cpp
|
||||
hle/service/bcat/bcat.h
|
||||
hle/service/bcat/bcat_result.h
|
||||
@@ -537,6 +527,18 @@ add_library(core STATIC
|
||||
hle/service/bcat/delivery_cache_progress_service.h
|
||||
hle/service/bcat/delivery_cache_storage_service.cpp
|
||||
hle/service/bcat/delivery_cache_storage_service.h
|
||||
hle/service/bcat/news/newly_arrived_event_holder.cpp
|
||||
hle/service/bcat/news/newly_arrived_event_holder.h
|
||||
hle/service/bcat/news/news_data_service.cpp
|
||||
hle/service/bcat/news/news_data_service.h
|
||||
hle/service/bcat/news/news_database_service.cpp
|
||||
hle/service/bcat/news/news_database_service.h
|
||||
hle/service/bcat/news/news_service.cpp
|
||||
hle/service/bcat/news/news_service.h
|
||||
hle/service/bcat/news/overwrite_event_holder.cpp
|
||||
hle/service/bcat/news/overwrite_event_holder.h
|
||||
hle/service/bcat/news/service_creator.cpp
|
||||
hle/service/bcat/news/service_creator.h
|
||||
hle/service/bcat/service_creator.cpp
|
||||
hle/service/bcat/service_creator.h
|
||||
hle/service/bpc/bpc.cpp
|
||||
@@ -545,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
|
||||
@@ -600,8 +612,6 @@ add_library(core STATIC
|
||||
hle/service/filesystem/romfs_controller.h
|
||||
hle/service/filesystem/save_data_controller.cpp
|
||||
hle/service/filesystem/save_data_controller.h
|
||||
hle/service/fgm/fgm.cpp
|
||||
hle/service/fgm/fgm.h
|
||||
hle/service/friend/friend.cpp
|
||||
hle/service/friend/friend.h
|
||||
hle/service/friend/friend_interface.cpp
|
||||
@@ -739,15 +749,48 @@ add_library(core STATIC
|
||||
hle/service/nim/nim.h
|
||||
hle/service/npns/npns.cpp
|
||||
hle/service/npns/npns.h
|
||||
hle/service/ns/errors.h
|
||||
hle/service/ns/iplatform_service_manager.cpp
|
||||
hle/service/ns/iplatform_service_manager.h
|
||||
hle/service/ns/account_proxy_interface.cpp
|
||||
hle/service/ns/account_proxy_interface.h
|
||||
hle/service/ns/application_manager_interface.cpp
|
||||
hle/service/ns/application_manager_interface.h
|
||||
hle/service/ns/application_version_interface.cpp
|
||||
hle/service/ns/application_version_interface.h
|
||||
hle/service/ns/content_management_interface.cpp
|
||||
hle/service/ns/content_management_interface.h
|
||||
hle/service/ns/develop_interface.cpp
|
||||
hle/service/ns/develop_interface.h
|
||||
hle/service/ns/document_interface.cpp
|
||||
hle/service/ns/document_interface.h
|
||||
hle/service/ns/download_task_interface.cpp
|
||||
hle/service/ns/download_task_interface.h
|
||||
hle/service/ns/dynamic_rights_interface.cpp
|
||||
hle/service/ns/dynamic_rights_interface.h
|
||||
hle/service/ns/ecommerce_interface.cpp
|
||||
hle/service/ns/ecommerce_interface.h
|
||||
hle/service/ns/factory_reset_interface.cpp
|
||||
hle/service/ns/factory_reset_interface.h
|
||||
hle/service/ns/language.cpp
|
||||
hle/service/ns/language.h
|
||||
hle/service/ns/ns.cpp
|
||||
hle/service/ns/ns.h
|
||||
hle/service/ns/pdm_qry.cpp
|
||||
hle/service/ns/pdm_qry.h
|
||||
hle/service/ns/ns_results.h
|
||||
hle/service/ns/ns_types.h
|
||||
hle/service/ns/platform_service_manager.cpp
|
||||
hle/service/ns/platform_service_manager.h
|
||||
hle/service/ns/query_service.cpp
|
||||
hle/service/ns/query_service.h
|
||||
hle/service/ns/read_only_application_control_data_interface.cpp
|
||||
hle/service/ns/read_only_application_control_data_interface.h
|
||||
hle/service/ns/read_only_application_record_interface.cpp
|
||||
hle/service/ns/read_only_application_record_interface.h
|
||||
hle/service/ns/service_getter_interface.cpp
|
||||
hle/service/ns/service_getter_interface.h
|
||||
hle/service/ns/system_update_control.cpp
|
||||
hle/service/ns/system_update_control.h
|
||||
hle/service/ns/system_update_interface.cpp
|
||||
hle/service/ns/system_update_interface.h
|
||||
hle/service/ns/vulnerability_manager_interface.cpp
|
||||
hle/service/ns/vulnerability_manager_interface.h
|
||||
hle/service/nvdrv/core/container.cpp
|
||||
hle/service/nvdrv/core/container.h
|
||||
hle/service/nvdrv/core/heap_mapper.cpp
|
||||
@@ -800,14 +843,14 @@ add_library(core STATIC
|
||||
hle/service/nvnflinger/consumer_base.cpp
|
||||
hle/service/nvnflinger/consumer_base.h
|
||||
hle/service/nvnflinger/consumer_listener.h
|
||||
hle/service/nvnflinger/fb_share_buffer_manager.cpp
|
||||
hle/service/nvnflinger/fb_share_buffer_manager.h
|
||||
hle/service/nvnflinger/graphic_buffer_producer.cpp
|
||||
hle/service/nvnflinger/graphic_buffer_producer.h
|
||||
hle/service/nvnflinger/hos_binder_driver_server.cpp
|
||||
hle/service/nvnflinger/hos_binder_driver_server.h
|
||||
hle/service/nvnflinger/hardware_composer.cpp
|
||||
hle/service/nvnflinger/hardware_composer.h
|
||||
hle/service/nvnflinger/hos_binder_driver.cpp
|
||||
hle/service/nvnflinger/hos_binder_driver.h
|
||||
hle/service/nvnflinger/hos_binder_driver_server.cpp
|
||||
hle/service/nvnflinger/hos_binder_driver_server.h
|
||||
hle/service/nvnflinger/hwc_layer.h
|
||||
hle/service/nvnflinger/nvnflinger.cpp
|
||||
hle/service/nvnflinger/nvnflinger.h
|
||||
@@ -815,6 +858,8 @@ add_library(core STATIC
|
||||
hle/service/nvnflinger/pixel_format.h
|
||||
hle/service/nvnflinger/producer_listener.h
|
||||
hle/service/nvnflinger/status.h
|
||||
hle/service/nvnflinger/surface_flinger.cpp
|
||||
hle/service/nvnflinger/surface_flinger.h
|
||||
hle/service/nvnflinger/ui/fence.h
|
||||
hle/service/nvnflinger/ui/graphic_buffer.cpp
|
||||
hle/service/nvnflinger/ui/graphic_buffer.h
|
||||
@@ -831,11 +876,11 @@ add_library(core STATIC
|
||||
hle/service/omm/power_state_interface.h
|
||||
hle/service/os/event.cpp
|
||||
hle/service/os/event.h
|
||||
hle/service/os/multi_wait.cpp
|
||||
hle/service/os/multi_wait.h
|
||||
hle/service/os/multi_wait_holder.cpp
|
||||
hle/service/os/multi_wait_holder.h
|
||||
hle/service/os/multi_wait_utils.h
|
||||
hle/service/os/multi_wait.cpp
|
||||
hle/service/os/multi_wait.h
|
||||
hle/service/os/mutex.cpp
|
||||
hle/service/os/mutex.h
|
||||
hle/service/pcie/pcie.cpp
|
||||
@@ -873,15 +918,17 @@ add_library(core STATIC
|
||||
hle/service/psc/time/common.cpp
|
||||
hle/service/psc/time/common.h
|
||||
hle/service/psc/time/errors.h
|
||||
hle/service/psc/time/shared_memory.cpp
|
||||
hle/service/psc/time/shared_memory.h
|
||||
hle/service/psc/time/static.cpp
|
||||
hle/service/psc/time/static.h
|
||||
hle/service/psc/time/manager.h
|
||||
hle/service/psc/time/power_state_request_manager.cpp
|
||||
hle/service/psc/time/power_state_request_manager.h
|
||||
hle/service/psc/time/power_state_service.cpp
|
||||
hle/service/psc/time/power_state_service.h
|
||||
hle/service/psc/time/service_manager.cpp
|
||||
hle/service/psc/time/service_manager.h
|
||||
hle/service/psc/time/shared_memory.cpp
|
||||
hle/service/psc/time/shared_memory.h
|
||||
hle/service/psc/time/static.cpp
|
||||
hle/service/psc/time/static.h
|
||||
hle/service/psc/time/steady_clock.cpp
|
||||
hle/service/psc/time/steady_clock.h
|
||||
hle/service/psc/time/system_clock.cpp
|
||||
@@ -890,8 +937,6 @@ add_library(core STATIC
|
||||
hle/service/psc/time/time_zone.h
|
||||
hle/service/psc/time/time_zone_service.cpp
|
||||
hle/service/psc/time/time_zone_service.h
|
||||
hle/service/psc/time/power_state_request_manager.cpp
|
||||
hle/service/psc/time/power_state_request_manager.h
|
||||
hle/service/ptm/psm.cpp
|
||||
hle/service/ptm/psm.h
|
||||
hle/service/ptm/ptm.cpp
|
||||
@@ -908,19 +953,21 @@ add_library(core STATIC
|
||||
hle/service/server_manager.h
|
||||
hle/service/service.cpp
|
||||
hle/service/service.h
|
||||
hle/service/set/setting_formats/appln_settings.cpp
|
||||
hle/service/set/setting_formats/appln_settings.h
|
||||
hle/service/set/setting_formats/device_settings.cpp
|
||||
hle/service/set/setting_formats/device_settings.h
|
||||
hle/service/set/setting_formats/system_settings.cpp
|
||||
hle/service/set/setting_formats/system_settings.h
|
||||
hle/service/set/setting_formats/private_settings.cpp
|
||||
hle/service/set/setting_formats/private_settings.h
|
||||
hle/service/services.cpp
|
||||
hle/service/services.h
|
||||
hle/service/set/factory_settings_server.cpp
|
||||
hle/service/set/factory_settings_server.h
|
||||
hle/service/set/firmware_debug_settings_server.cpp
|
||||
hle/service/set/firmware_debug_settings_server.h
|
||||
hle/service/set/key_code_map.h
|
||||
hle/service/set/setting_formats/appln_settings.cpp
|
||||
hle/service/set/setting_formats/appln_settings.h
|
||||
hle/service/set/setting_formats/device_settings.cpp
|
||||
hle/service/set/setting_formats/device_settings.h
|
||||
hle/service/set/setting_formats/private_settings.cpp
|
||||
hle/service/set/setting_formats/private_settings.h
|
||||
hle/service/set/setting_formats/system_settings.cpp
|
||||
hle/service/set/setting_formats/system_settings.h
|
||||
hle/service/set/settings.cpp
|
||||
hle/service/set/settings.h
|
||||
hle/service/set/settings_server.cpp
|
||||
@@ -955,30 +1002,36 @@ add_library(core STATIC
|
||||
hle/service/ssl/ssl_backend.h
|
||||
hle/service/usb/usb.cpp
|
||||
hle/service/usb/usb.h
|
||||
hle/service/vi/display/vi_display.cpp
|
||||
hle/service/vi/display/vi_display.h
|
||||
hle/service/vi/layer/vi_layer.cpp
|
||||
hle/service/vi/layer/vi_layer.h
|
||||
hle/service/vi/application_display_service.cpp
|
||||
hle/service/vi/application_display_service.h
|
||||
hle/service/vi/application_root_service.cpp
|
||||
hle/service/vi/application_root_service.h
|
||||
hle/service/vi/hos_binder_driver.cpp
|
||||
hle/service/vi/hos_binder_driver.h
|
||||
hle/service/vi/conductor.cpp
|
||||
hle/service/vi/conductor.h
|
||||
hle/service/vi/container.cpp
|
||||
hle/service/vi/container.h
|
||||
hle/service/vi/display.h
|
||||
hle/service/vi/display_list.h
|
||||
hle/service/vi/layer.h
|
||||
hle/service/vi/layer_list.h
|
||||
hle/service/vi/manager_display_service.cpp
|
||||
hle/service/vi/manager_display_service.h
|
||||
hle/service/vi/manager_root_service.cpp
|
||||
hle/service/vi/manager_root_service.h
|
||||
hle/service/vi/service_creator.cpp
|
||||
hle/service/vi/service_creator.h
|
||||
hle/service/vi/shared_buffer_manager.cpp
|
||||
hle/service/vi/shared_buffer_manager.h
|
||||
hle/service/vi/system_display_service.cpp
|
||||
hle/service/vi/system_display_service.h
|
||||
hle/service/vi/system_root_service.cpp
|
||||
hle/service/vi/system_root_service.h
|
||||
hle/service/vi/vi_results.h
|
||||
hle/service/vi/vi_types.h
|
||||
hle/service/vi/vi.cpp
|
||||
hle/service/vi/vi.h
|
||||
hle/service/vi/vi_results.h
|
||||
hle/service/vi/vi_types.h
|
||||
hle/service/vi/vsync_manager.cpp
|
||||
hle/service/vi/vsync_manager.h
|
||||
internal_network/network.cpp
|
||||
internal_network/network.h
|
||||
internal_network/network_interface.cpp
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#include "core/hle/service/psc/time/system_clock.h"
|
||||
#include "core/hle/service/psc/time/time_zone_service.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/services.h"
|
||||
#include "core/hle/service/set/system_settings_server.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
#include "core/internal_network/network.h"
|
||||
@@ -310,7 +311,8 @@ struct System::Impl {
|
||||
audio_core = std::make_unique<AudioCore::AudioCore>(system);
|
||||
|
||||
service_manager = std::make_shared<Service::SM::ServiceManager>(kernel);
|
||||
services = std::make_unique<Service::Services>(service_manager, system);
|
||||
services =
|
||||
std::make_unique<Service::Services>(service_manager, system, stop_event.get_token());
|
||||
|
||||
is_powered_on = true;
|
||||
exit_locked = false;
|
||||
@@ -458,11 +460,10 @@ struct System::Impl {
|
||||
gpu_core->NotifyShutdown();
|
||||
}
|
||||
|
||||
stop_event.request_stop();
|
||||
core_timing.SyncPause(false);
|
||||
Network::CancelPendingSocketOperations();
|
||||
kernel.SuspendEmulation(true);
|
||||
if (services) {
|
||||
services->KillNVNFlinger();
|
||||
}
|
||||
kernel.CloseServices();
|
||||
kernel.ShutdownCores();
|
||||
applet_manager.Reset();
|
||||
@@ -480,6 +481,7 @@ struct System::Impl {
|
||||
cpu_manager.Shutdown();
|
||||
debugger.reset();
|
||||
kernel.Shutdown();
|
||||
stop_event = {};
|
||||
Network::RestartSocketOperations();
|
||||
|
||||
if (auto room_member = room_network.GetRoomMember().lock()) {
|
||||
@@ -615,6 +617,7 @@ struct System::Impl {
|
||||
|
||||
ExecuteProgramCallback execute_program_callback;
|
||||
ExitCallback exit_callback;
|
||||
std::stop_source stop_event;
|
||||
|
||||
std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};
|
||||
std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_cpu{};
|
||||
|
||||
@@ -199,10 +199,10 @@ void CpuManager::RunThread(std::stop_token token, std::size_t core) {
|
||||
data.host_context = Common::Fiber::ThreadToFiber();
|
||||
|
||||
// Cleanup
|
||||
SCOPE_EXIT({
|
||||
SCOPE_EXIT {
|
||||
data.host_context->Exit();
|
||||
MicroProfileOnThreadExit();
|
||||
});
|
||||
};
|
||||
|
||||
// Running
|
||||
if (!gpu_barrier->Sync(token)) {
|
||||
|
||||
@@ -43,6 +43,8 @@ public:
|
||||
DeviceMemoryManager(const DeviceMemory& device_memory);
|
||||
~DeviceMemoryManager();
|
||||
|
||||
static constexpr bool HAS_FLUSH_INVALIDATION = true;
|
||||
|
||||
void BindInterface(DeviceInterface* device_inter);
|
||||
|
||||
DAddr Allocate(size_t size);
|
||||
|
||||
@@ -391,12 +391,12 @@ void DeviceMemoryManager<Traits>::WalkBlock(DAddr addr, std::size_t size, auto o
|
||||
std::min((next_pages << Memory::YUZU_PAGEBITS) - page_offset, remaining_size);
|
||||
const auto current_vaddr =
|
||||
static_cast<u64>((page_index << Memory::YUZU_PAGEBITS) + page_offset);
|
||||
SCOPE_EXIT({
|
||||
SCOPE_EXIT{
|
||||
page_index += next_pages;
|
||||
page_offset = 0;
|
||||
increment(copy_amount);
|
||||
remaining_size -= copy_amount;
|
||||
});
|
||||
};
|
||||
|
||||
auto phys_addr = compressed_physical_ptr[page_index];
|
||||
if (phys_addr == 0) {
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
constexpr inline size_t EntryNameLengthMax = 0x300;
|
||||
|
||||
@@ -23,6 +23,8 @@ enum class OpenDirectoryMode : u64 {
|
||||
File = (1 << 1),
|
||||
|
||||
All = (Directory | File),
|
||||
|
||||
NotRequireFileSize = (1ULL << 31),
|
||||
};
|
||||
DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode)
|
||||
|
||||
@@ -36,4 +38,29 @@ enum class CreateOption : u8 {
|
||||
BigFile = (1 << 0),
|
||||
};
|
||||
|
||||
struct FileSystemAttribute {
|
||||
u8 dir_entry_name_length_max_defined;
|
||||
u8 file_entry_name_length_max_defined;
|
||||
u8 dir_path_name_length_max_defined;
|
||||
u8 file_path_name_length_max_defined;
|
||||
INSERT_PADDING_BYTES_NOINIT(0x5);
|
||||
u8 utf16_dir_entry_name_length_max_defined;
|
||||
u8 utf16_file_entry_name_length_max_defined;
|
||||
u8 utf16_dir_path_name_length_max_defined;
|
||||
u8 utf16_file_path_name_length_max_defined;
|
||||
INSERT_PADDING_BYTES_NOINIT(0x18);
|
||||
s32 dir_entry_name_length_max;
|
||||
s32 file_entry_name_length_max;
|
||||
s32 dir_path_name_length_max;
|
||||
s32 file_path_name_length_max;
|
||||
INSERT_PADDING_WORDS_NOINIT(0x5);
|
||||
s32 utf16_dir_entry_name_length_max;
|
||||
s32 utf16_file_entry_name_length_max;
|
||||
s32 utf16_dir_path_name_length_max;
|
||||
s32 utf16_file_path_name_length_max;
|
||||
INSERT_PADDING_WORDS_NOINIT(0x18);
|
||||
INSERT_PADDING_WORDS_NOINIT(0x1);
|
||||
};
|
||||
static_assert(sizeof(FileSystemAttribute) == 0xC0, "FileSystemAttribute has incorrect size");
|
||||
|
||||
} // namespace FileSys
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace FileSys {
|
||||
|
||||
constexpr size_t RequiredAlignment = alignof(u64);
|
||||
|
||||
void* AllocateUnsafe(size_t size) {
|
||||
inline void* AllocateUnsafe(size_t size) {
|
||||
// Allocate
|
||||
void* const ptr = ::operator new(size, std::align_val_t{RequiredAlignment});
|
||||
|
||||
@@ -21,16 +21,16 @@ void* AllocateUnsafe(size_t size) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void DeallocateUnsafe(void* ptr, size_t size) {
|
||||
inline void DeallocateUnsafe(void* ptr, size_t size) {
|
||||
// Deallocate the pointer
|
||||
::operator delete(ptr, std::align_val_t{RequiredAlignment});
|
||||
}
|
||||
|
||||
void* Allocate(size_t size) {
|
||||
inline void* Allocate(size_t size) {
|
||||
return AllocateUnsafe(size);
|
||||
}
|
||||
|
||||
void Deallocate(void* ptr, size_t size) {
|
||||
inline void Deallocate(void* ptr, size_t size) {
|
||||
// If the pointer is non-null, deallocate it
|
||||
if (ptr != nullptr) {
|
||||
DeallocateUnsafe(ptr, size);
|
||||
|
||||
@@ -381,7 +381,7 @@ public:
|
||||
|
||||
// Check that it's possible for us to remove a child
|
||||
auto* p = m_write_buffer.Get();
|
||||
s32 len = std::strlen(p);
|
||||
s32 len = static_cast<s32>(std::strlen(p));
|
||||
R_UNLESS(len != 1 || (p[0] != '/' && p[0] != '.'), ResultNotImplemented);
|
||||
|
||||
// Handle a trailing separator
|
||||
|
||||
@@ -426,9 +426,10 @@ public:
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
static Result Normalize(char* dst, size_t* out_len, const char* path, size_t max_out_size,
|
||||
bool is_windows_path, bool is_drive_relative_path,
|
||||
bool allow_all_characters = false) {
|
||||
static constexpr Result Normalize(char* dst, size_t* out_len, const char* path,
|
||||
size_t max_out_size, bool is_windows_path,
|
||||
bool is_drive_relative_path,
|
||||
bool allow_all_characters = false) {
|
||||
// Use StringTraits names for remainder of scope
|
||||
using namespace StringTraits;
|
||||
|
||||
@@ -447,7 +448,7 @@ public:
|
||||
char* replacement_path = nullptr;
|
||||
size_t replacement_path_size = 0;
|
||||
|
||||
SCOPE_EXIT({
|
||||
SCOPE_EXIT {
|
||||
if (replacement_path != nullptr) {
|
||||
if (std::is_constant_evaluated()) {
|
||||
delete[] replacement_path;
|
||||
@@ -455,7 +456,7 @@ public:
|
||||
Deallocate(replacement_path, replacement_path_size);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Perform path replacement, if necessary
|
||||
if (IsParentDirectoryPathReplacementNeeded(cur_path)) {
|
||||
@@ -1102,8 +1103,8 @@ public:
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
static Result Normalize(char* dst, size_t dst_size, const char* path, size_t path_len,
|
||||
const PathFlags& flags) {
|
||||
static constexpr Result Normalize(char* dst, size_t dst_size, const char* path, size_t path_len,
|
||||
const PathFlags& flags) {
|
||||
// Use StringTraits names for remainder of scope
|
||||
using namespace StringTraits;
|
||||
|
||||
@@ -1199,7 +1200,7 @@ public:
|
||||
const size_t replaced_src_len = path_len - (src - path);
|
||||
|
||||
char* replaced_src = nullptr;
|
||||
SCOPE_EXIT({
|
||||
SCOPE_EXIT {
|
||||
if (replaced_src != nullptr) {
|
||||
if (std::is_constant_evaluated()) {
|
||||
delete[] replaced_src;
|
||||
@@ -1207,7 +1208,7 @@ public:
|
||||
Deallocate(replaced_src, replaced_src_len);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if (std::is_constant_evaluated()) {
|
||||
replaced_src = new char[replaced_src_len];
|
||||
|
||||
@@ -19,6 +19,11 @@ constexpr int Strlen(const T* str) {
|
||||
return length;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr int Strnlen(const T* str, std::size_t count) {
|
||||
return Strnlen(str, static_cast<int>(count));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr int Strnlen(const T* str, int count) {
|
||||
ASSERT(str != nullptr);
|
||||
@@ -32,6 +37,11 @@ constexpr int Strnlen(const T* str, int count) {
|
||||
return length;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr int Strncmp(const T* lhs, const T* rhs, std::size_t count) {
|
||||
return Strncmp(lhs, rhs, static_cast<int>(count));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr int Strncmp(const T* lhs, const T* rhs, int count) {
|
||||
ASSERT(lhs != nullptr);
|
||||
@@ -51,6 +61,11 @@ constexpr int Strncmp(const T* lhs, const T* rhs, int count) {
|
||||
return l - r;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static constexpr int Strlcpy(T* dst, const T* src, std::size_t count) {
|
||||
return Strlcpy<T>(dst, src, static_cast<int>(count));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static constexpr int Strlcpy(T* dst, const T* src, int count) {
|
||||
ASSERT(dst != nullptr);
|
||||
|
||||
91
src/core/file_sys/fsa/fs_i_directory.h
Normal file
91
src/core/file_sys/fsa/fs_i_directory.h
Normal file
@@ -0,0 +1,91 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/file_sys/errors.h"
|
||||
#include "core/file_sys/fs_directory.h"
|
||||
#include "core/file_sys/fs_file.h"
|
||||
#include "core/file_sys/fs_filesystem.h"
|
||||
#include "core/file_sys/savedata_factory.h"
|
||||
#include "core/file_sys/vfs/vfs.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace FileSys::Fsa {
|
||||
|
||||
class IDirectory {
|
||||
public:
|
||||
explicit IDirectory(VirtualDir backend_, OpenDirectoryMode mode)
|
||||
: backend(std::move(backend_)) {
|
||||
// TODO(DarkLordZach): Verify that this is the correct behavior.
|
||||
// Build entry index now to save time later.
|
||||
if (True(mode & OpenDirectoryMode::Directory)) {
|
||||
BuildEntryIndex(backend->GetSubdirectories(), DirectoryEntryType::Directory);
|
||||
}
|
||||
if (True(mode & OpenDirectoryMode::File)) {
|
||||
BuildEntryIndex(backend->GetFiles(), DirectoryEntryType::File);
|
||||
}
|
||||
}
|
||||
virtual ~IDirectory() {}
|
||||
|
||||
Result Read(s64* out_count, DirectoryEntry* out_entries, s64 max_entries) {
|
||||
R_UNLESS(out_count != nullptr, ResultNullptrArgument);
|
||||
if (max_entries == 0) {
|
||||
*out_count = 0;
|
||||
R_SUCCEED();
|
||||
}
|
||||
R_UNLESS(out_entries != nullptr, ResultNullptrArgument);
|
||||
R_UNLESS(max_entries > 0, ResultInvalidArgument);
|
||||
R_RETURN(this->DoRead(out_count, out_entries, max_entries));
|
||||
}
|
||||
|
||||
Result GetEntryCount(s64* out) {
|
||||
R_UNLESS(out != nullptr, ResultNullptrArgument);
|
||||
R_RETURN(this->DoGetEntryCount(out));
|
||||
}
|
||||
|
||||
private:
|
||||
Result DoRead(s64* out_count, DirectoryEntry* out_entries, s64 max_entries) {
|
||||
const u64 actual_entries =
|
||||
std::min(static_cast<u64>(max_entries), entries.size() - next_entry_index);
|
||||
const auto* begin = reinterpret_cast<u8*>(entries.data() + next_entry_index);
|
||||
const auto* end = reinterpret_cast<u8*>(entries.data() + next_entry_index + actual_entries);
|
||||
const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
|
||||
|
||||
next_entry_index += actual_entries;
|
||||
*out_count = actual_entries;
|
||||
|
||||
std::memcpy(out_entries, begin, range_size);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result DoGetEntryCount(s64* out) {
|
||||
*out = entries.size() - next_entry_index;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
// TODO: Remove this when VFS is gone
|
||||
template <typename T>
|
||||
void BuildEntryIndex(const std::vector<T>& new_data, DirectoryEntryType type) {
|
||||
entries.reserve(entries.size() + new_data.size());
|
||||
|
||||
for (const auto& new_entry : new_data) {
|
||||
auto name = new_entry->GetName();
|
||||
|
||||
if (type == DirectoryEntryType::File && name == GetSaveDataSizeFileName()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
entries.emplace_back(name, static_cast<s8>(type),
|
||||
type == DirectoryEntryType::Directory ? 0 : new_entry->GetSize());
|
||||
}
|
||||
}
|
||||
|
||||
VirtualDir backend;
|
||||
std::vector<DirectoryEntry> entries;
|
||||
u64 next_entry_index = 0;
|
||||
};
|
||||
|
||||
} // namespace FileSys::Fsa
|
||||
167
src/core/file_sys/fsa/fs_i_file.h
Normal file
167
src/core/file_sys/fsa/fs_i_file.h
Normal file
@@ -0,0 +1,167 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/overflow.h"
|
||||
#include "core/file_sys/errors.h"
|
||||
#include "core/file_sys/fs_file.h"
|
||||
#include "core/file_sys/fs_filesystem.h"
|
||||
#include "core/file_sys/fs_operate_range.h"
|
||||
#include "core/file_sys/vfs/vfs.h"
|
||||
#include "core/file_sys/vfs/vfs_types.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace FileSys::Fsa {
|
||||
|
||||
class IFile {
|
||||
public:
|
||||
explicit IFile(VirtualFile backend_) : backend(std::move(backend_)) {}
|
||||
virtual ~IFile() {}
|
||||
|
||||
Result Read(size_t* out, s64 offset, void* buffer, size_t size, const ReadOption& option) {
|
||||
// Check that we have an output pointer
|
||||
R_UNLESS(out != nullptr, ResultNullptrArgument);
|
||||
|
||||
// If we have nothing to read, just succeed
|
||||
if (size == 0) {
|
||||
*out = 0;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
// Check that the read is valid
|
||||
R_UNLESS(buffer != nullptr, ResultNullptrArgument);
|
||||
R_UNLESS(offset >= 0, ResultOutOfRange);
|
||||
R_UNLESS(Common::CanAddWithoutOverflow<s64>(offset, size), ResultOutOfRange);
|
||||
|
||||
// Do the read
|
||||
R_RETURN(this->DoRead(out, offset, buffer, size, option));
|
||||
}
|
||||
|
||||
Result Read(size_t* out, s64 offset, void* buffer, size_t size) {
|
||||
R_RETURN(this->Read(out, offset, buffer, size, ReadOption::None));
|
||||
}
|
||||
|
||||
Result GetSize(s64* out) {
|
||||
R_UNLESS(out != nullptr, ResultNullptrArgument);
|
||||
R_RETURN(this->DoGetSize(out));
|
||||
}
|
||||
|
||||
Result Flush() {
|
||||
R_RETURN(this->DoFlush());
|
||||
}
|
||||
|
||||
Result Write(s64 offset, const void* buffer, size_t size, const WriteOption& option) {
|
||||
// Handle the zero-size case
|
||||
if (size == 0) {
|
||||
if (option.HasFlushFlag()) {
|
||||
R_TRY(this->Flush());
|
||||
}
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
// Check the write is valid
|
||||
R_UNLESS(buffer != nullptr, ResultNullptrArgument);
|
||||
R_UNLESS(offset >= 0, ResultOutOfRange);
|
||||
R_UNLESS(Common::CanAddWithoutOverflow<s64>(offset, size), ResultOutOfRange);
|
||||
|
||||
R_RETURN(this->DoWrite(offset, buffer, size, option));
|
||||
}
|
||||
|
||||
Result SetSize(s64 size) {
|
||||
R_UNLESS(size >= 0, ResultOutOfRange);
|
||||
R_RETURN(this->DoSetSize(size));
|
||||
}
|
||||
|
||||
Result OperateRange(void* dst, size_t dst_size, OperationId op_id, s64 offset, s64 size,
|
||||
const void* src, size_t src_size) {
|
||||
R_RETURN(this->DoOperateRange(dst, dst_size, op_id, offset, size, src, src_size));
|
||||
}
|
||||
|
||||
Result OperateRange(OperationId op_id, s64 offset, s64 size) {
|
||||
R_RETURN(this->DoOperateRange(nullptr, 0, op_id, offset, size, nullptr, 0));
|
||||
}
|
||||
|
||||
protected:
|
||||
Result DryRead(size_t* out, s64 offset, size_t size, const ReadOption& option,
|
||||
OpenMode open_mode) {
|
||||
// Check that we can read
|
||||
R_UNLESS(static_cast<u32>(open_mode & OpenMode::Read) != 0, ResultReadNotPermitted);
|
||||
|
||||
// Get the file size, and validate our offset
|
||||
s64 file_size = 0;
|
||||
R_TRY(this->DoGetSize(std::addressof(file_size)));
|
||||
R_UNLESS(offset <= file_size, ResultOutOfRange);
|
||||
|
||||
*out = static_cast<size_t>(std::min(file_size - offset, static_cast<s64>(size)));
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result DrySetSize(s64 size, OpenMode open_mode) {
|
||||
// Check that we can write
|
||||
R_UNLESS(static_cast<u32>(open_mode & OpenMode::Write) != 0, ResultWriteNotPermitted);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result DryWrite(bool* out_append, s64 offset, size_t size, const WriteOption& option,
|
||||
OpenMode open_mode) {
|
||||
// Check that we can write
|
||||
R_UNLESS(static_cast<u32>(open_mode & OpenMode::Write) != 0, ResultWriteNotPermitted);
|
||||
|
||||
// Get the file size
|
||||
s64 file_size = 0;
|
||||
R_TRY(this->DoGetSize(&file_size));
|
||||
|
||||
// Determine if we need to append
|
||||
*out_append = false;
|
||||
if (file_size < offset + static_cast<s64>(size)) {
|
||||
R_UNLESS(static_cast<u32>(open_mode & OpenMode::AllowAppend) != 0,
|
||||
ResultFileExtensionWithoutOpenModeAllowAppend);
|
||||
*out_append = true;
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
private:
|
||||
Result DoRead(size_t* out, s64 offset, void* buffer, size_t size, const ReadOption& option) {
|
||||
const auto read_size = backend->Read(static_cast<u8*>(buffer), size, offset);
|
||||
*out = read_size;
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result DoGetSize(s64* out) {
|
||||
*out = backend->GetSize();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result DoFlush() {
|
||||
// Exists for SDK compatibiltity -- No need to flush file.
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result DoWrite(s64 offset, const void* buffer, size_t size, const WriteOption& option) {
|
||||
const std::size_t written = backend->Write(static_cast<const u8*>(buffer), size, offset);
|
||||
|
||||
ASSERT_MSG(written == size,
|
||||
"Could not write all bytes to file (requested={:016X}, actual={:016X}).", size,
|
||||
written);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result DoSetSize(s64 size) {
|
||||
backend->Resize(size);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result DoOperateRange(void* dst, size_t dst_size, OperationId op_id, s64 offset, s64 size,
|
||||
const void* src, size_t src_size) {
|
||||
R_THROW(ResultNotImplemented);
|
||||
}
|
||||
|
||||
VirtualFile backend;
|
||||
};
|
||||
|
||||
} // namespace FileSys::Fsa
|
||||
206
src/core/file_sys/fsa/fs_i_filesystem.h
Normal file
206
src/core/file_sys/fsa/fs_i_filesystem.h
Normal file
@@ -0,0 +1,206 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/file_sys/errors.h"
|
||||
#include "core/file_sys/fs_filesystem.h"
|
||||
#include "core/file_sys/fs_path.h"
|
||||
#include "core/file_sys/vfs/vfs_types.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
|
||||
namespace FileSys::Fsa {
|
||||
|
||||
class IFile;
|
||||
class IDirectory;
|
||||
|
||||
enum class QueryId : u32 {
|
||||
SetConcatenationFileAttribute = 0,
|
||||
UpdateMac = 1,
|
||||
IsSignedSystemPartitionOnSdCardValid = 2,
|
||||
QueryUnpreparedFileInformation = 3,
|
||||
};
|
||||
|
||||
class IFileSystem {
|
||||
public:
|
||||
explicit IFileSystem(VirtualDir backend_) : backend{std::move(backend_)} {}
|
||||
virtual ~IFileSystem() {}
|
||||
|
||||
Result CreateFile(const Path& path, s64 size, CreateOption option) {
|
||||
R_UNLESS(size >= 0, ResultOutOfRange);
|
||||
R_RETURN(this->DoCreateFile(path, size, static_cast<int>(option)));
|
||||
}
|
||||
|
||||
Result CreateFile(const Path& path, s64 size) {
|
||||
R_RETURN(this->CreateFile(path, size, CreateOption::None));
|
||||
}
|
||||
|
||||
Result DeleteFile(const Path& path) {
|
||||
R_RETURN(this->DoDeleteFile(path));
|
||||
}
|
||||
|
||||
Result CreateDirectory(const Path& path) {
|
||||
R_RETURN(this->DoCreateDirectory(path));
|
||||
}
|
||||
|
||||
Result DeleteDirectory(const Path& path) {
|
||||
R_RETURN(this->DoDeleteDirectory(path));
|
||||
}
|
||||
|
||||
Result DeleteDirectoryRecursively(const Path& path) {
|
||||
R_RETURN(this->DoDeleteDirectoryRecursively(path));
|
||||
}
|
||||
|
||||
Result RenameFile(const Path& old_path, const Path& new_path) {
|
||||
R_RETURN(this->DoRenameFile(old_path, new_path));
|
||||
}
|
||||
|
||||
Result RenameDirectory(const Path& old_path, const Path& new_path) {
|
||||
R_RETURN(this->DoRenameDirectory(old_path, new_path));
|
||||
}
|
||||
|
||||
Result GetEntryType(DirectoryEntryType* out, const Path& path) {
|
||||
R_RETURN(this->DoGetEntryType(out, path));
|
||||
}
|
||||
|
||||
Result OpenFile(VirtualFile* out_file, const Path& path, OpenMode mode) {
|
||||
R_UNLESS(out_file != nullptr, ResultNullptrArgument);
|
||||
R_UNLESS(static_cast<u32>(mode & OpenMode::ReadWrite) != 0, ResultInvalidOpenMode);
|
||||
R_UNLESS(static_cast<u32>(mode & ~OpenMode::All) == 0, ResultInvalidOpenMode);
|
||||
R_RETURN(this->DoOpenFile(out_file, path, mode));
|
||||
}
|
||||
|
||||
Result OpenDirectory(VirtualDir* out_dir, const Path& path, OpenDirectoryMode mode) {
|
||||
R_UNLESS(out_dir != nullptr, ResultNullptrArgument);
|
||||
R_UNLESS(static_cast<u64>(mode & OpenDirectoryMode::All) != 0, ResultInvalidOpenMode);
|
||||
R_UNLESS(static_cast<u64>(
|
||||
mode & ~(OpenDirectoryMode::All | OpenDirectoryMode::NotRequireFileSize)) == 0,
|
||||
ResultInvalidOpenMode);
|
||||
R_RETURN(this->DoOpenDirectory(out_dir, path, mode));
|
||||
}
|
||||
|
||||
Result Commit() {
|
||||
R_RETURN(this->DoCommit());
|
||||
}
|
||||
|
||||
Result GetFreeSpaceSize(s64* out, const Path& path) {
|
||||
R_UNLESS(out != nullptr, ResultNullptrArgument);
|
||||
R_RETURN(this->DoGetFreeSpaceSize(out, path));
|
||||
}
|
||||
|
||||
Result GetTotalSpaceSize(s64* out, const Path& path) {
|
||||
R_UNLESS(out != nullptr, ResultNullptrArgument);
|
||||
R_RETURN(this->DoGetTotalSpaceSize(out, path));
|
||||
}
|
||||
|
||||
Result CleanDirectoryRecursively(const Path& path) {
|
||||
R_RETURN(this->DoCleanDirectoryRecursively(path));
|
||||
}
|
||||
|
||||
Result GetFileTimeStampRaw(FileTimeStampRaw* out, const Path& path) {
|
||||
R_UNLESS(out != nullptr, ResultNullptrArgument);
|
||||
R_RETURN(this->DoGetFileTimeStampRaw(out, path));
|
||||
}
|
||||
|
||||
Result QueryEntry(char* dst, size_t dst_size, const char* src, size_t src_size, QueryId query,
|
||||
const Path& path) {
|
||||
R_RETURN(this->DoQueryEntry(dst, dst_size, src, src_size, query, path));
|
||||
}
|
||||
|
||||
// These aren't accessible as commands
|
||||
Result CommitProvisionally(s64 counter) {
|
||||
R_RETURN(this->DoCommitProvisionally(counter));
|
||||
}
|
||||
|
||||
Result Rollback() {
|
||||
R_RETURN(this->DoRollback());
|
||||
}
|
||||
|
||||
Result Flush() {
|
||||
R_RETURN(this->DoFlush());
|
||||
}
|
||||
|
||||
private:
|
||||
Result DoCreateFile(const Path& path, s64 size, int flags) {
|
||||
R_RETURN(backend.CreateFile(path.GetString(), size));
|
||||
}
|
||||
|
||||
Result DoDeleteFile(const Path& path) {
|
||||
R_RETURN(backend.DeleteFile(path.GetString()));
|
||||
}
|
||||
|
||||
Result DoCreateDirectory(const Path& path) {
|
||||
R_RETURN(backend.CreateDirectory(path.GetString()));
|
||||
}
|
||||
|
||||
Result DoDeleteDirectory(const Path& path) {
|
||||
R_RETURN(backend.DeleteDirectory(path.GetString()));
|
||||
}
|
||||
|
||||
Result DoDeleteDirectoryRecursively(const Path& path) {
|
||||
R_RETURN(backend.DeleteDirectoryRecursively(path.GetString()));
|
||||
}
|
||||
|
||||
Result DoRenameFile(const Path& old_path, const Path& new_path) {
|
||||
R_RETURN(backend.RenameFile(old_path.GetString(), new_path.GetString()));
|
||||
}
|
||||
|
||||
Result DoRenameDirectory(const Path& old_path, const Path& new_path) {
|
||||
R_RETURN(backend.RenameDirectory(old_path.GetString(), new_path.GetString()));
|
||||
}
|
||||
|
||||
Result DoGetEntryType(DirectoryEntryType* out, const Path& path) {
|
||||
R_RETURN(backend.GetEntryType(out, path.GetString()));
|
||||
}
|
||||
|
||||
Result DoOpenFile(VirtualFile* out_file, const Path& path, OpenMode mode) {
|
||||
R_RETURN(backend.OpenFile(out_file, path.GetString(), mode));
|
||||
}
|
||||
|
||||
Result DoOpenDirectory(VirtualDir* out_directory, const Path& path, OpenDirectoryMode mode) {
|
||||
R_RETURN(backend.OpenDirectory(out_directory, path.GetString()));
|
||||
}
|
||||
|
||||
Result DoCommit() {
|
||||
R_THROW(ResultNotImplemented);
|
||||
}
|
||||
|
||||
Result DoGetFreeSpaceSize(s64* out, const Path& path) {
|
||||
R_THROW(ResultNotImplemented);
|
||||
}
|
||||
|
||||
Result DoGetTotalSpaceSize(s64* out, const Path& path) {
|
||||
R_THROW(ResultNotImplemented);
|
||||
}
|
||||
|
||||
Result DoCleanDirectoryRecursively(const Path& path) {
|
||||
R_RETURN(backend.CleanDirectoryRecursively(path.GetString()));
|
||||
}
|
||||
|
||||
Result DoGetFileTimeStampRaw(FileTimeStampRaw* out, const Path& path) {
|
||||
R_RETURN(backend.GetFileTimeStampRaw(out, path.GetString()));
|
||||
}
|
||||
|
||||
Result DoQueryEntry(char* dst, size_t dst_size, const char* src, size_t src_size, QueryId query,
|
||||
const Path& path) {
|
||||
R_THROW(ResultNotImplemented);
|
||||
}
|
||||
|
||||
// These aren't accessible as commands
|
||||
Result DoCommitProvisionally(s64 counter) {
|
||||
R_THROW(ResultNotImplemented);
|
||||
}
|
||||
|
||||
Result DoRollback() {
|
||||
R_THROW(ResultNotImplemented);
|
||||
}
|
||||
|
||||
Result DoFlush() {
|
||||
R_THROW(ResultNotImplemented);
|
||||
}
|
||||
|
||||
Service::FileSystem::VfsDirectoryServiceWrapper backend;
|
||||
};
|
||||
|
||||
} // namespace FileSys::Fsa
|
||||
36
src/core/file_sys/fssrv/fssrv_sf_path.h
Normal file
36
src/core/file_sys/fssrv/fssrv_sf_path.h
Normal file
@@ -0,0 +1,36 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/file_sys/fs_directory.h"
|
||||
|
||||
namespace FileSys::Sf {
|
||||
|
||||
struct Path {
|
||||
char str[EntryNameLengthMax + 1];
|
||||
|
||||
static constexpr Path Encode(const char* p) {
|
||||
Path path = {};
|
||||
for (size_t i = 0; i < sizeof(path) - 1; i++) {
|
||||
path.str[i] = p[i];
|
||||
if (p[i] == '\x00') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
static constexpr size_t GetPathLength(const Path& path) {
|
||||
size_t len = 0;
|
||||
for (size_t i = 0; i < sizeof(path) - 1 && path.str[i] != '\x00'; i++) {
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
};
|
||||
static_assert(std::is_trivially_copyable_v<Path>, "Path must be trivially copyable.");
|
||||
|
||||
using FspPath = Path;
|
||||
|
||||
} // namespace FileSys::Sf
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
|
||||
#include "core/crypto/aes_util.h"
|
||||
|
||||
@@ -36,7 +36,9 @@ Result HierarchicalSha256Storage::Initialize(VirtualFile* base_storages, s32 lay
|
||||
// Get the base storage size.
|
||||
m_base_storage_size = base_storages[2]->GetSize();
|
||||
{
|
||||
auto size_guard = SCOPE_GUARD({ m_base_storage_size = 0; });
|
||||
auto size_guard = SCOPE_GUARD {
|
||||
m_base_storage_size = 0;
|
||||
};
|
||||
R_UNLESS(m_base_storage_size <= static_cast<s64>(HashSize)
|
||||
<< m_log_size_ratio << m_log_size_ratio,
|
||||
ResultHierarchicalSha256BaseStorageTooLarge);
|
||||
|
||||
@@ -98,7 +98,9 @@ Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) {
|
||||
|
||||
Loader::ResultStatus ProgramMetadata::Reload(VirtualFile file) {
|
||||
const u64 original_program_id = aci_header.title_id;
|
||||
SCOPE_EXIT({ aci_header.title_id = original_program_id; });
|
||||
SCOPE_EXIT {
|
||||
aci_header.title_id = original_program_id;
|
||||
};
|
||||
|
||||
return this->Load(file);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "core/file_sys/system_archive/data/font_standard.h"
|
||||
#include "core/file_sys/system_archive/shared_font.h"
|
||||
#include "core/file_sys/vfs/vfs_vector.h"
|
||||
#include "core/hle/service/ns/iplatform_service_manager.h"
|
||||
#include "core/hle/service/ns/platform_service_manager.h"
|
||||
|
||||
namespace FileSys::SystemArchive {
|
||||
|
||||
|
||||
@@ -44,15 +44,32 @@ public:
|
||||
GuestMemory() = delete;
|
||||
explicit GuestMemory(M& memory, u64 addr, std::size_t size,
|
||||
Common::ScratchBuffer<T>* backup = nullptr)
|
||||
: m_memory{memory}, m_addr{addr}, m_size{size} {
|
||||
: m_memory{&memory}, m_addr{addr}, m_size{size} {
|
||||
static_assert(FLAGS & GuestMemoryFlags::Read || FLAGS & GuestMemoryFlags::Write);
|
||||
if constexpr (FLAGS & GuestMemoryFlags::Read) {
|
||||
if constexpr (!(FLAGS & GuestMemoryFlags::Read)) {
|
||||
if (!this->TrySetSpan()) {
|
||||
if (backup) {
|
||||
backup->resize_destructive(this->size());
|
||||
m_data_span = *backup;
|
||||
m_span_valid = true;
|
||||
m_is_data_copy = true;
|
||||
} else {
|
||||
m_data_copy.resize(this->size());
|
||||
m_data_span = std::span(m_data_copy);
|
||||
m_span_valid = true;
|
||||
m_is_data_copy = true;
|
||||
}
|
||||
}
|
||||
} else if constexpr (FLAGS & GuestMemoryFlags::Read) {
|
||||
Read(addr, size, backup);
|
||||
}
|
||||
}
|
||||
|
||||
~GuestMemory() = default;
|
||||
|
||||
GuestMemory(GuestMemory&& rhs) = default;
|
||||
GuestMemory& operator=(GuestMemory&& rhs) = default;
|
||||
|
||||
T* data() noexcept {
|
||||
return m_data_span.data();
|
||||
}
|
||||
@@ -109,8 +126,8 @@ public:
|
||||
}
|
||||
|
||||
if (this->TrySetSpan()) {
|
||||
if constexpr (FLAGS & GuestMemoryFlags::Safe) {
|
||||
m_memory.FlushRegion(m_addr, this->size_bytes());
|
||||
if constexpr (FLAGS & GuestMemoryFlags::Safe && M::HAS_FLUSH_INVALIDATION) {
|
||||
m_memory->FlushRegion(m_addr, this->size_bytes());
|
||||
}
|
||||
} else {
|
||||
if (backup) {
|
||||
@@ -123,9 +140,9 @@ public:
|
||||
m_is_data_copy = true;
|
||||
m_span_valid = true;
|
||||
if constexpr (FLAGS & GuestMemoryFlags::Safe) {
|
||||
m_memory.ReadBlock(m_addr, this->data(), this->size_bytes());
|
||||
m_memory->ReadBlock(m_addr, this->data(), this->size_bytes());
|
||||
} else {
|
||||
m_memory.ReadBlockUnsafe(m_addr, this->data(), this->size_bytes());
|
||||
m_memory->ReadBlockUnsafe(m_addr, this->data(), this->size_bytes());
|
||||
}
|
||||
}
|
||||
return m_data_span;
|
||||
@@ -133,18 +150,19 @@ public:
|
||||
|
||||
void Write(std::span<T> write_data) noexcept {
|
||||
if constexpr (FLAGS & GuestMemoryFlags::Cached) {
|
||||
m_memory.WriteBlockCached(m_addr, write_data.data(), this->size_bytes());
|
||||
m_memory->WriteBlockCached(m_addr, write_data.data(), this->size_bytes());
|
||||
} else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
|
||||
m_memory.WriteBlock(m_addr, write_data.data(), this->size_bytes());
|
||||
m_memory->WriteBlock(m_addr, write_data.data(), this->size_bytes());
|
||||
} else {
|
||||
m_memory.WriteBlockUnsafe(m_addr, write_data.data(), this->size_bytes());
|
||||
m_memory->WriteBlockUnsafe(m_addr, write_data.data(), this->size_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
bool TrySetSpan() noexcept {
|
||||
if (u8* ptr = m_memory.GetSpan(m_addr, this->size_bytes()); ptr) {
|
||||
if (u8* ptr = m_memory->GetSpan(m_addr, this->size_bytes()); ptr) {
|
||||
m_data_span = {reinterpret_cast<T*>(ptr), this->size()};
|
||||
m_span_valid = true;
|
||||
m_is_data_copy = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -159,7 +177,7 @@ protected:
|
||||
return m_addr_changed;
|
||||
}
|
||||
|
||||
M& m_memory;
|
||||
M* m_memory;
|
||||
u64 m_addr{};
|
||||
size_t m_size{};
|
||||
std::span<T> m_data_span{};
|
||||
@@ -175,17 +193,7 @@ public:
|
||||
GuestMemoryScoped() = delete;
|
||||
explicit GuestMemoryScoped(M& memory, u64 addr, std::size_t size,
|
||||
Common::ScratchBuffer<T>* backup = nullptr)
|
||||
: GuestMemory<M, T, FLAGS>(memory, addr, size, backup) {
|
||||
if constexpr (!(FLAGS & GuestMemoryFlags::Read)) {
|
||||
if (!this->TrySetSpan()) {
|
||||
if (backup) {
|
||||
this->m_data_span = *backup;
|
||||
this->m_span_valid = true;
|
||||
this->m_is_data_copy = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
: GuestMemory<M, T, FLAGS>(memory, addr, size, backup) {}
|
||||
|
||||
~GuestMemoryScoped() {
|
||||
if constexpr (FLAGS & GuestMemoryFlags::Write) {
|
||||
@@ -196,15 +204,17 @@ public:
|
||||
if (this->AddressChanged() || this->IsDataCopy()) {
|
||||
ASSERT(this->m_span_valid);
|
||||
if constexpr (FLAGS & GuestMemoryFlags::Cached) {
|
||||
this->m_memory.WriteBlockCached(this->m_addr, this->data(), this->size_bytes());
|
||||
this->m_memory->WriteBlockCached(this->m_addr, this->data(),
|
||||
this->size_bytes());
|
||||
} else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
|
||||
this->m_memory.WriteBlock(this->m_addr, this->data(), this->size_bytes());
|
||||
this->m_memory->WriteBlock(this->m_addr, this->data(), this->size_bytes());
|
||||
} else {
|
||||
this->m_memory.WriteBlockUnsafe(this->m_addr, this->data(), this->size_bytes());
|
||||
this->m_memory->WriteBlockUnsafe(this->m_addr, this->data(),
|
||||
this->size_bytes());
|
||||
}
|
||||
} else if constexpr ((FLAGS & GuestMemoryFlags::Safe) ||
|
||||
(FLAGS & GuestMemoryFlags::Cached)) {
|
||||
this->m_memory.InvalidateRegion(this->m_addr, this->size_bytes());
|
||||
this->m_memory->InvalidateRegion(this->m_addr, this->size_bytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,9 @@ Result KClientSession::SendSyncRequest(uintptr_t address, size_t size) {
|
||||
// Create a session request.
|
||||
KSessionRequest* request = KSessionRequest::Create(m_kernel);
|
||||
R_UNLESS(request != nullptr, ResultOutOfResource);
|
||||
SCOPE_EXIT({ request->Close(); });
|
||||
SCOPE_EXIT {
|
||||
request->Close();
|
||||
};
|
||||
|
||||
// Initialize the request.
|
||||
request->Initialize(nullptr, address, size);
|
||||
@@ -37,7 +39,9 @@ Result KClientSession::SendAsyncRequest(KEvent* event, uintptr_t address, size_t
|
||||
// Create a session request.
|
||||
KSessionRequest* request = KSessionRequest::Create(m_kernel);
|
||||
R_UNLESS(request != nullptr, ResultOutOfResource);
|
||||
SCOPE_EXIT({ request->Close(); });
|
||||
SCOPE_EXIT {
|
||||
request->Close();
|
||||
};
|
||||
|
||||
// Initialize the request.
|
||||
request->Initialize(event, address, size);
|
||||
|
||||
@@ -1305,11 +1305,11 @@ Result KPageTableBase::UnmapCodeMemory(KProcessAddress dst_address, KProcessAddr
|
||||
|
||||
// Ensure that we maintain the instruction cache.
|
||||
bool reprotected_pages = false;
|
||||
SCOPE_EXIT({
|
||||
SCOPE_EXIT {
|
||||
if (reprotected_pages && any_code_pages) {
|
||||
InvalidateInstructionCache(m_kernel, this, dst_address, size);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Unmap.
|
||||
{
|
||||
@@ -1397,7 +1397,9 @@ Result KPageTableBase::MapInsecureMemory(KProcessAddress address, size_t size) {
|
||||
// Close the opened pages when we're done with them.
|
||||
// If the mapping succeeds, each page will gain an extra reference, otherwise they will be freed
|
||||
// automatically.
|
||||
SCOPE_EXIT({ pg.Close(); });
|
||||
SCOPE_EXIT {
|
||||
pg.Close();
|
||||
};
|
||||
|
||||
// Clear all the newly allocated pages.
|
||||
for (const auto& it : pg) {
|
||||
@@ -1603,7 +1605,9 @@ Result KPageTableBase::AllocateAndMapPagesImpl(PageLinkedList* page_list, KProce
|
||||
m_kernel.MemoryManager().AllocateAndOpen(std::addressof(pg), num_pages, m_allocate_option));
|
||||
|
||||
// Ensure that the page group is closed when we're done working with it.
|
||||
SCOPE_EXIT({ pg.Close(); });
|
||||
SCOPE_EXIT {
|
||||
pg.Close();
|
||||
};
|
||||
|
||||
// Clear all pages.
|
||||
for (const auto& it : pg) {
|
||||
@@ -2191,7 +2195,9 @@ Result KPageTableBase::SetHeapSize(KProcessAddress* out, size_t size) {
|
||||
// Close the opened pages when we're done with them.
|
||||
// If the mapping succeeds, each page will gain an extra reference, otherwise they will be freed
|
||||
// automatically.
|
||||
SCOPE_EXIT({ pg.Close(); });
|
||||
SCOPE_EXIT {
|
||||
pg.Close();
|
||||
};
|
||||
|
||||
// Clear all the newly allocated pages.
|
||||
for (const auto& it : pg) {
|
||||
@@ -2592,7 +2598,9 @@ Result KPageTableBase::UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddre
|
||||
// Temporarily unlock ourselves, so that other operations can occur while we flush the
|
||||
// region.
|
||||
m_general_lock.Unlock();
|
||||
SCOPE_EXIT({ m_general_lock.Lock(); });
|
||||
SCOPE_EXIT {
|
||||
m_general_lock.Lock();
|
||||
};
|
||||
|
||||
// Flush the region.
|
||||
R_ASSERT(FlushDataCache(dst_address, size));
|
||||
@@ -3311,10 +3319,10 @@ Result KPageTableBase::ReadIoMemoryImpl(KProcessAddress dst_addr, KPhysicalAddre
|
||||
// Ensure we unmap the io memory when we're done with it.
|
||||
const KPageProperties unmap_properties =
|
||||
KPageProperties{KMemoryPermission::None, false, false, DisableMergeAttribute::None};
|
||||
SCOPE_EXIT({
|
||||
SCOPE_EXIT {
|
||||
R_ASSERT(this->Operate(updater.GetPageList(), io_addr, map_size / PageSize, 0, false,
|
||||
unmap_properties, OperationType::Unmap, true));
|
||||
});
|
||||
};
|
||||
|
||||
// Read the memory.
|
||||
const KProcessAddress read_addr = io_addr + (GetInteger(phys_addr) & (PageSize - 1));
|
||||
@@ -3347,10 +3355,10 @@ Result KPageTableBase::WriteIoMemoryImpl(KPhysicalAddress phys_addr, KProcessAdd
|
||||
// Ensure we unmap the io memory when we're done with it.
|
||||
const KPageProperties unmap_properties =
|
||||
KPageProperties{KMemoryPermission::None, false, false, DisableMergeAttribute::None};
|
||||
SCOPE_EXIT({
|
||||
SCOPE_EXIT {
|
||||
R_ASSERT(this->Operate(updater.GetPageList(), io_addr, map_size / PageSize, 0, false,
|
||||
unmap_properties, OperationType::Unmap, true));
|
||||
});
|
||||
};
|
||||
|
||||
// Write the memory.
|
||||
const KProcessAddress write_addr = io_addr + (GetInteger(phys_addr) & (PageSize - 1));
|
||||
@@ -4491,14 +4499,14 @@ Result KPageTableBase::SetupForIpcServer(KProcessAddress* out_addr, size_t size,
|
||||
|
||||
// If the partial pages are mapped, an extra reference will have been opened. Otherwise, they'll
|
||||
// free on scope exit.
|
||||
SCOPE_EXIT({
|
||||
SCOPE_EXIT {
|
||||
if (start_partial_page != 0) {
|
||||
m_kernel.MemoryManager().Close(start_partial_page, 1);
|
||||
}
|
||||
if (end_partial_page != 0) {
|
||||
m_kernel.MemoryManager().Close(end_partial_page, 1);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
ON_RESULT_FAILURE {
|
||||
if (cur_mapped_addr != dst_addr) {
|
||||
@@ -5166,10 +5174,10 @@ Result KPageTableBase::MapPhysicalMemory(KProcessAddress address, size_t size) {
|
||||
GetCurrentProcess(m_kernel).GetId(), m_heap_fill_value));
|
||||
|
||||
// If we fail in the next bit (or retry), we need to cleanup the pages.
|
||||
auto pg_guard = SCOPE_GUARD({
|
||||
auto pg_guard = SCOPE_GUARD {
|
||||
pg.OpenFirst();
|
||||
pg.Close();
|
||||
});
|
||||
};
|
||||
|
||||
// Map the memory.
|
||||
{
|
||||
@@ -5694,7 +5702,9 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
|
||||
|
||||
// Ensure that any pages we track are closed on exit.
|
||||
KPageGroup pages_to_close(m_kernel, this->GetBlockInfoManager());
|
||||
SCOPE_EXIT({ pages_to_close.CloseAndReset(); });
|
||||
SCOPE_EXIT {
|
||||
pages_to_close.CloseAndReset();
|
||||
};
|
||||
|
||||
// Make a page group representing the region to unmap.
|
||||
this->MakePageGroup(pages_to_close, virt_addr, num_pages);
|
||||
|
||||
@@ -77,7 +77,9 @@ Result TerminateChildren(KernelCore& kernel, KProcess* process,
|
||||
}
|
||||
|
||||
// Terminate and close the thread.
|
||||
SCOPE_EXIT({ cur_child->Close(); });
|
||||
SCOPE_EXIT {
|
||||
cur_child->Close();
|
||||
};
|
||||
|
||||
if (const Result terminate_result = cur_child->Terminate();
|
||||
ResultTerminationRequested == terminate_result) {
|
||||
@@ -466,11 +468,11 @@ void KProcess::DoWorkerTaskImpl() {
|
||||
|
||||
Result KProcess::StartTermination() {
|
||||
// Finalize the handle table when we're done, if the process isn't immortal.
|
||||
SCOPE_EXIT({
|
||||
SCOPE_EXIT {
|
||||
if (!m_is_immortal) {
|
||||
this->FinalizeHandleTable();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Terminate child threads other than the current one.
|
||||
R_RETURN(TerminateChildren(m_kernel, this, GetCurrentThreadPointer(m_kernel)));
|
||||
@@ -964,7 +966,9 @@ Result KProcess::Run(s32 priority, size_t stack_size) {
|
||||
// Create a new thread for the process.
|
||||
KThread* main_thread = KThread::Create(m_kernel);
|
||||
R_UNLESS(main_thread != nullptr, ResultOutOfResource);
|
||||
SCOPE_EXIT({ main_thread->Close(); });
|
||||
SCOPE_EXIT {
|
||||
main_thread->Close();
|
||||
};
|
||||
|
||||
// Initialize the thread.
|
||||
R_TRY(KThread::InitializeUserThread(m_kernel.System(), main_thread, this->GetEntryPoint(), 0,
|
||||
@@ -1155,7 +1159,9 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
|
||||
Kernel::CreateResourceLimitForProcess(m_kernel.System(), physical_memory_size);
|
||||
|
||||
// Ensure we maintain a clean state on exit.
|
||||
SCOPE_EXIT({ res_limit->Close(); });
|
||||
SCOPE_EXIT {
|
||||
res_limit->Close();
|
||||
};
|
||||
|
||||
// Declare flags and code address.
|
||||
Svc::CreateProcessFlag flag{};
|
||||
|
||||
@@ -651,11 +651,11 @@ Result ReceiveMessage(KernelCore& kernel, bool& recv_list_broken, uint64_t dst_m
|
||||
// Process any special data.
|
||||
if (src_header.GetHasSpecialHeader()) {
|
||||
// After we process, make sure we track whether the receive list is broken.
|
||||
SCOPE_EXIT({
|
||||
SCOPE_EXIT {
|
||||
if (offset > dst_recv_list_idx) {
|
||||
recv_list_broken = true;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Process special data.
|
||||
R_TRY(ProcessMessageSpecialData<false>(offset, dst_process, src_process, src_thread,
|
||||
@@ -665,11 +665,11 @@ Result ReceiveMessage(KernelCore& kernel, bool& recv_list_broken, uint64_t dst_m
|
||||
// Process any pointer buffers.
|
||||
for (auto i = 0; i < src_header.GetPointerCount(); ++i) {
|
||||
// After we process, make sure we track whether the receive list is broken.
|
||||
SCOPE_EXIT({
|
||||
SCOPE_EXIT {
|
||||
if (offset > dst_recv_list_idx) {
|
||||
recv_list_broken = true;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
R_TRY(ProcessReceiveMessagePointerDescriptors(
|
||||
offset, pointer_key, dst_page_table, src_page_table, dst_msg, src_msg, dst_recv_list,
|
||||
@@ -680,11 +680,11 @@ Result ReceiveMessage(KernelCore& kernel, bool& recv_list_broken, uint64_t dst_m
|
||||
// Process any map alias buffers.
|
||||
for (auto i = 0; i < src_header.GetMapAliasCount(); ++i) {
|
||||
// After we process, make sure we track whether the receive list is broken.
|
||||
SCOPE_EXIT({
|
||||
SCOPE_EXIT {
|
||||
if (offset > dst_recv_list_idx) {
|
||||
recv_list_broken = true;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// We process in order send, recv, exch. Buffers after send (recv/exch) are ReadWrite.
|
||||
const KMemoryPermission perm = (i >= src_header.GetSendCount())
|
||||
@@ -702,11 +702,11 @@ Result ReceiveMessage(KernelCore& kernel, bool& recv_list_broken, uint64_t dst_m
|
||||
// Process any raw data.
|
||||
if (const auto raw_count = src_header.GetRawCount(); raw_count != 0) {
|
||||
// After we process, make sure we track whether the receive list is broken.
|
||||
SCOPE_EXIT({
|
||||
SCOPE_EXIT {
|
||||
if (offset + raw_count > dst_recv_list_idx) {
|
||||
recv_list_broken = true;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Get the offset and size.
|
||||
const size_t offset_words = offset * sizeof(u32);
|
||||
@@ -1124,7 +1124,9 @@ Result KServerSession::ReceiveRequest(uintptr_t server_message, uintptr_t server
|
||||
client_thread->Open();
|
||||
}
|
||||
|
||||
SCOPE_EXIT({ client_thread->Close(); });
|
||||
SCOPE_EXIT {
|
||||
client_thread->Close();
|
||||
};
|
||||
|
||||
// Set the request as our current.
|
||||
m_current_request = request;
|
||||
@@ -1174,7 +1176,9 @@ Result KServerSession::ReceiveRequest(uintptr_t server_message, uintptr_t server
|
||||
// Reply to the client.
|
||||
{
|
||||
// After we reply, close our reference to the request.
|
||||
SCOPE_EXIT({ request->Close(); });
|
||||
SCOPE_EXIT {
|
||||
request->Close();
|
||||
};
|
||||
|
||||
// Get the event to check whether the request is async.
|
||||
if (KEvent* event = request->GetEvent(); event != nullptr) {
|
||||
@@ -1236,7 +1240,9 @@ Result KServerSession::SendReply(uintptr_t server_message, uintptr_t server_buff
|
||||
}
|
||||
|
||||
// Close reference to the request once we're done processing it.
|
||||
SCOPE_EXIT({ request->Close(); });
|
||||
SCOPE_EXIT {
|
||||
request->Close();
|
||||
};
|
||||
|
||||
// Extract relevant information from the request.
|
||||
const uint64_t client_message = request->GetAddress();
|
||||
@@ -1394,7 +1400,9 @@ void KServerSession::CleanupRequests() {
|
||||
}
|
||||
|
||||
// Close a reference to the request once it's cleaned up.
|
||||
SCOPE_EXIT({ request->Close(); });
|
||||
SCOPE_EXIT {
|
||||
request->Close();
|
||||
};
|
||||
|
||||
// Extract relevant information from the request.
|
||||
const uint64_t client_message = request->GetAddress();
|
||||
@@ -1491,7 +1499,9 @@ void KServerSession::OnClientClosed() {
|
||||
ASSERT(thread != nullptr);
|
||||
|
||||
// Ensure that we close the request when done.
|
||||
SCOPE_EXIT({ request->Close(); });
|
||||
SCOPE_EXIT {
|
||||
request->Close();
|
||||
};
|
||||
|
||||
// If we're terminating, close a reference to the thread and event.
|
||||
if (terminate) {
|
||||
|
||||
@@ -21,7 +21,9 @@ Result KThreadLocalPage::Initialize(KernelCore& kernel, KProcess* process) {
|
||||
// Allocate a new page.
|
||||
KPageBuffer* page_buf = KPageBuffer::Allocate(kernel);
|
||||
R_UNLESS(page_buf != nullptr, ResultOutOfMemory);
|
||||
auto page_buf_guard = SCOPE_GUARD({ KPageBuffer::Free(kernel, page_buf); });
|
||||
auto page_buf_guard = SCOPE_GUARD {
|
||||
KPageBuffer::Free(kernel, page_buf);
|
||||
};
|
||||
|
||||
// Map the address in.
|
||||
const auto phys_addr = kernel.System().DeviceMemory().GetPhysicalAddr(page_buf);
|
||||
|
||||
@@ -24,7 +24,9 @@ Result KTransferMemory::Initialize(KProcessAddress addr, std::size_t size,
|
||||
|
||||
// Construct the page group, guarding to make sure our state is valid on exit.
|
||||
m_page_group.emplace(m_kernel, page_table.GetBlockInfoManager());
|
||||
auto pg_guard = SCOPE_GUARD({ m_page_group.reset(); });
|
||||
auto pg_guard = SCOPE_GUARD {
|
||||
m_page_group.reset();
|
||||
};
|
||||
|
||||
// Lock the memory.
|
||||
R_TRY(page_table.LockForTransferMemory(std::addressof(*m_page_group), addr, size,
|
||||
|
||||
@@ -109,7 +109,9 @@ struct KernelCore::Impl {
|
||||
|
||||
void Shutdown() {
|
||||
is_shutting_down.store(true, std::memory_order_relaxed);
|
||||
SCOPE_EXIT({ is_shutting_down.store(false, std::memory_order_relaxed); });
|
||||
SCOPE_EXIT {
|
||||
is_shutting_down.store(false, std::memory_order_relaxed);
|
||||
};
|
||||
|
||||
CloseServices();
|
||||
|
||||
@@ -1080,7 +1082,9 @@ std::jthread KernelCore::RunOnHostCoreProcess(std::string&& process_name,
|
||||
process->Initialize(Svc::CreateProcessParameter{}, GetSystemResourceLimit(), false)));
|
||||
|
||||
// Ensure that we don't hold onto any extra references.
|
||||
SCOPE_EXIT({ process->Close(); });
|
||||
SCOPE_EXIT {
|
||||
process->Close();
|
||||
};
|
||||
|
||||
// Register the new process.
|
||||
KProcess::Register(*this, process);
|
||||
@@ -1108,7 +1112,9 @@ void KernelCore::RunOnGuestCoreProcess(std::string&& process_name, std::function
|
||||
process->Initialize(Svc::CreateProcessParameter{}, GetSystemResourceLimit(), false)));
|
||||
|
||||
// Ensure that we don't hold onto any extra references.
|
||||
SCOPE_EXIT({ process->Close(); });
|
||||
SCOPE_EXIT {
|
||||
process->Close();
|
||||
};
|
||||
|
||||
// Register the new process.
|
||||
KProcess::Register(*this, process);
|
||||
|
||||
@@ -45,7 +45,9 @@ Result CreateCodeMemory(Core::System& system, Handle* out, u64 address, uint64_t
|
||||
|
||||
KCodeMemory* code_mem = KCodeMemory::Create(kernel);
|
||||
R_UNLESS(code_mem != nullptr, ResultOutOfResource);
|
||||
SCOPE_EXIT({ code_mem->Close(); });
|
||||
SCOPE_EXIT {
|
||||
code_mem->Close();
|
||||
};
|
||||
|
||||
// Verify that the region is in range.
|
||||
R_UNLESS(GetCurrentProcess(system.Kernel()).GetPageTable().Contains(address, size),
|
||||
|
||||
@@ -28,7 +28,9 @@ Result CreateDeviceAddressSpace(Core::System& system, Handle* out, uint64_t das_
|
||||
// Create the device address space.
|
||||
KDeviceAddressSpace* das = KDeviceAddressSpace::Create(system.Kernel());
|
||||
R_UNLESS(das != nullptr, ResultOutOfResource);
|
||||
SCOPE_EXIT({ das->Close(); });
|
||||
SCOPE_EXIT {
|
||||
das->Close();
|
||||
};
|
||||
|
||||
// Initialize the device address space.
|
||||
R_TRY(das->Initialize(das_address, das_size));
|
||||
|
||||
@@ -72,10 +72,10 @@ Result CreateEvent(Core::System& system, Handle* out_write, Handle* out_read) {
|
||||
event_reservation.Commit();
|
||||
|
||||
// Ensure that we clean up the event (and its only references are handle table) on function end.
|
||||
SCOPE_EXIT({
|
||||
SCOPE_EXIT {
|
||||
event->GetReadableEvent().Close();
|
||||
event->Close();
|
||||
});
|
||||
};
|
||||
|
||||
// Register the event.
|
||||
KEvent::Register(kernel, event);
|
||||
|
||||
@@ -129,11 +129,11 @@ Result ReplyAndReceiveImpl(KernelCore& kernel, int32_t* out_index, uintptr_t mes
|
||||
}
|
||||
|
||||
// Ensure handles are closed when we're done.
|
||||
SCOPE_EXIT({
|
||||
SCOPE_EXIT {
|
||||
for (auto i = 0; i < num_handles; ++i) {
|
||||
objs[i]->Close();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
R_RETURN(ReplyAndReceiveImpl(kernel, out_index, message, buffer_size, message_paddr, objs,
|
||||
num_handles, reply_target, timeout_ns));
|
||||
@@ -208,10 +208,10 @@ Result SendAsyncRequestWithUserBuffer(Core::System& system, Handle* out_event_ha
|
||||
event_reservation.Commit();
|
||||
|
||||
// At end of scope, kill the standing references to the sub events.
|
||||
SCOPE_EXIT({
|
||||
SCOPE_EXIT {
|
||||
event->GetReadableEvent().Close();
|
||||
event->Close();
|
||||
});
|
||||
};
|
||||
|
||||
// Register the event.
|
||||
KEvent::Register(system.Kernel(), event);
|
||||
|
||||
@@ -68,10 +68,10 @@ Result CreatePort(Core::System& system, Handle* out_server, Handle* out_client,
|
||||
port->Initialize(max_sessions, is_light, name);
|
||||
|
||||
// Ensure that we clean up the port (and its only references are handle table) on function end.
|
||||
SCOPE_EXIT({
|
||||
SCOPE_EXIT {
|
||||
port->GetServerPort().Close();
|
||||
port->GetClientPort().Close();
|
||||
});
|
||||
};
|
||||
|
||||
// Register the port.
|
||||
KPort::Register(kernel, port);
|
||||
@@ -150,10 +150,10 @@ Result ManageNamedPort(Core::System& system, Handle* out_server_handle, uint64_t
|
||||
KPort::Register(system.Kernel(), port);
|
||||
|
||||
// Ensure that our only reference to the port is in the handle table when we're done.
|
||||
SCOPE_EXIT({
|
||||
SCOPE_EXIT {
|
||||
port->GetClientPort().Close();
|
||||
port->GetServerPort().Close();
|
||||
});
|
||||
};
|
||||
|
||||
// Register the handle in the table.
|
||||
R_TRY(handle_table.Add(out_server_handle, std::addressof(port->GetServerPort())));
|
||||
|
||||
@@ -18,7 +18,9 @@ Result CreateResourceLimit(Core::System& system, Handle* out_handle) {
|
||||
R_UNLESS(resource_limit != nullptr, ResultOutOfResource);
|
||||
|
||||
// Ensure we don't leak a reference to the limit.
|
||||
SCOPE_EXIT({ resource_limit->Close(); });
|
||||
SCOPE_EXIT {
|
||||
resource_limit->Close();
|
||||
};
|
||||
|
||||
// Initialize the resource limit.
|
||||
resource_limit->Initialize();
|
||||
|
||||
@@ -69,10 +69,10 @@ Result CreateSession(Core::System& system, Handle* out_server, Handle* out_clien
|
||||
|
||||
// Ensure that we clean up the session (and its only references are handle table) on function
|
||||
// end.
|
||||
SCOPE_EXIT({
|
||||
SCOPE_EXIT {
|
||||
session->GetClientSession().Close();
|
||||
session->GetServerSession().Close();
|
||||
});
|
||||
};
|
||||
|
||||
// Register the session.
|
||||
T::Register(system.Kernel(), session);
|
||||
|
||||
@@ -78,11 +78,11 @@ Result WaitSynchronization(Core::System& system, int32_t* out_index, u64 user_ha
|
||||
}
|
||||
|
||||
// Ensure handles are closed when we're done.
|
||||
SCOPE_EXIT({
|
||||
SCOPE_EXIT {
|
||||
for (auto i = 0; i < num_handles; ++i) {
|
||||
objs[i]->Close();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Convert the timeout from nanoseconds to ticks.
|
||||
s64 timeout;
|
||||
|
||||
@@ -51,7 +51,9 @@ Result CreateThread(Core::System& system, Handle* out_handle, u64 entry_point, u
|
||||
// Create the thread.
|
||||
KThread* thread = KThread::Create(kernel);
|
||||
R_UNLESS(thread != nullptr, ResultOutOfResource)
|
||||
SCOPE_EXIT({ thread->Close(); });
|
||||
SCOPE_EXIT {
|
||||
thread->Close();
|
||||
};
|
||||
|
||||
// Initialize the thread.
|
||||
{
|
||||
|
||||
@@ -52,7 +52,9 @@ Result CreateTransferMemory(Core::System& system, Handle* out, u64 address, u64
|
||||
R_UNLESS(trmem != nullptr, ResultOutOfResource);
|
||||
|
||||
// Ensure the only reference is in the handle table when we're done.
|
||||
SCOPE_EXIT({ trmem->Close(); });
|
||||
SCOPE_EXIT {
|
||||
trmem->Close();
|
||||
};
|
||||
|
||||
// Ensure that the region is in range.
|
||||
R_UNLESS(process.GetPageTable().Contains(address, size), ResultInvalidCurrentMemory);
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) {
|
||||
void LoopProcess(Core::System& system) {
|
||||
auto server_manager = std::make_unique<ServerManager>(system);
|
||||
|
||||
server_manager->RegisterNamedService(
|
||||
"appletAE", std::make_shared<IAllSystemAppletProxiesService>(system, nvnflinger));
|
||||
server_manager->RegisterNamedService(
|
||||
"appletOE", std::make_shared<IApplicationProxyService>(system, nvnflinger));
|
||||
server_manager->RegisterNamedService("appletAE",
|
||||
std::make_shared<IAllSystemAppletProxiesService>(system));
|
||||
server_manager->RegisterNamedService("appletOE",
|
||||
std::make_shared<IApplicationProxyService>(system));
|
||||
ServerManager::RunServer(std::move(server_manager));
|
||||
}
|
||||
|
||||
|
||||
@@ -7,12 +7,8 @@ namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::Nvnflinger {
|
||||
class Nvnflinger;
|
||||
}
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system);
|
||||
void LoopProcess(Core::System& system);
|
||||
|
||||
} // namespace Service::AM
|
||||
|
||||
@@ -14,10 +14,9 @@
|
||||
|
||||
#include "core/hle/service/am/am_types.h"
|
||||
#include "core/hle/service/am/applet_message_queue.h"
|
||||
#include "core/hle/service/am/display_layer_manager.h"
|
||||
#include "core/hle/service/am/hid_registration.h"
|
||||
#include "core/hle/service/am/managed_layer_holder.h"
|
||||
#include "core/hle/service/am/process.h"
|
||||
#include "core/hle/service/am/system_buffer_manager.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
@@ -54,8 +53,7 @@ struct Applet {
|
||||
HidRegistration hid_registration;
|
||||
|
||||
// vi state
|
||||
SystemBufferManager system_buffer_manager{};
|
||||
ManagedLayerHolder managed_layer_holder{};
|
||||
DisplayLayerManager display_layer_manager{};
|
||||
|
||||
// Applet common functions
|
||||
Result terminate_result{};
|
||||
|
||||
@@ -24,11 +24,11 @@ void AppletStorageChannel::Push(std::shared_ptr<IStorage> storage) {
|
||||
Result AppletStorageChannel::Pop(std::shared_ptr<IStorage>* out_storage) {
|
||||
std::scoped_lock lk{m_lock};
|
||||
|
||||
SCOPE_EXIT({
|
||||
SCOPE_EXIT {
|
||||
if (m_data.empty()) {
|
||||
m_event.Clear();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
R_UNLESS(!m_data.empty(), AM::ResultNoDataInChannel);
|
||||
|
||||
|
||||
151
src/core/hle/service/am/display_layer_manager.cpp
Normal file
151
src/core/hle/service/am/display_layer_manager.cpp
Normal file
@@ -0,0 +1,151 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/am/display_layer_manager.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
#include "core/hle/service/vi/application_display_service.h"
|
||||
#include "core/hle/service/vi/container.h"
|
||||
#include "core/hle/service/vi/manager_display_service.h"
|
||||
#include "core/hle/service/vi/manager_root_service.h"
|
||||
#include "core/hle/service/vi/shared_buffer_manager.h"
|
||||
#include "core/hle/service/vi/vi_results.h"
|
||||
#include "core/hle/service/vi/vi_types.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
DisplayLayerManager::DisplayLayerManager() = default;
|
||||
DisplayLayerManager::~DisplayLayerManager() {
|
||||
this->Finalize();
|
||||
}
|
||||
|
||||
void DisplayLayerManager::Initialize(Core::System& system, Kernel::KProcess* process,
|
||||
AppletId applet_id, LibraryAppletMode mode) {
|
||||
R_ASSERT(system.ServiceManager()
|
||||
.GetService<VI::IManagerRootService>("vi:m", true)
|
||||
->GetDisplayService(&m_display_service, VI::Policy::Compositor));
|
||||
R_ASSERT(m_display_service->GetManagerDisplayService(&m_manager_display_service));
|
||||
|
||||
m_process = process;
|
||||
m_system_shared_buffer_id = 0;
|
||||
m_system_shared_layer_id = 0;
|
||||
m_applet_id = applet_id;
|
||||
m_buffer_sharing_enabled = false;
|
||||
m_blending_enabled = mode == LibraryAppletMode::PartialForeground ||
|
||||
mode == LibraryAppletMode::PartialForegroundIndirectDisplay;
|
||||
}
|
||||
|
||||
void DisplayLayerManager::Finalize() {
|
||||
if (!m_manager_display_service) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clean up managed layers.
|
||||
for (const auto& layer : m_managed_display_layers) {
|
||||
m_manager_display_service->DestroyManagedLayer(layer);
|
||||
}
|
||||
|
||||
for (const auto& layer : m_managed_display_recording_layers) {
|
||||
m_manager_display_service->DestroyManagedLayer(layer);
|
||||
}
|
||||
|
||||
// Clean up shared layers.
|
||||
if (m_buffer_sharing_enabled) {
|
||||
m_manager_display_service->DestroySharedLayerSession(m_process);
|
||||
}
|
||||
|
||||
m_manager_display_service = nullptr;
|
||||
m_display_service = nullptr;
|
||||
}
|
||||
|
||||
Result DisplayLayerManager::CreateManagedDisplayLayer(u64* out_layer_id) {
|
||||
R_UNLESS(m_manager_display_service != nullptr, VI::ResultOperationFailed);
|
||||
|
||||
// TODO(Subv): Find out how AM determines the display to use, for now just
|
||||
// create the layer in the Default display.
|
||||
u64 display_id;
|
||||
R_TRY(m_display_service->OpenDisplay(&display_id, VI::DisplayName{"Default"}));
|
||||
R_TRY(m_manager_display_service->CreateManagedLayer(
|
||||
out_layer_id, 0, display_id, Service::AppletResourceUserId{m_process->GetProcessId()}));
|
||||
|
||||
m_manager_display_service->SetLayerVisibility(m_visible, *out_layer_id);
|
||||
m_managed_display_layers.emplace(*out_layer_id);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result DisplayLayerManager::CreateManagedDisplaySeparableLayer(u64* out_layer_id,
|
||||
u64* out_recording_layer_id) {
|
||||
R_UNLESS(m_manager_display_service != nullptr, VI::ResultOperationFailed);
|
||||
|
||||
// TODO(Subv): Find out how AM determines the display to use, for now just
|
||||
// create the layer in the Default display.
|
||||
// This calls nn::vi::CreateRecordingLayer() which creates another layer.
|
||||
// Currently we do not support more than 1 layer per display, output 1 layer id for now.
|
||||
// Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse
|
||||
// side effects.
|
||||
*out_recording_layer_id = 0;
|
||||
R_RETURN(this->CreateManagedDisplayLayer(out_layer_id));
|
||||
}
|
||||
|
||||
Result DisplayLayerManager::IsSystemBufferSharingEnabled() {
|
||||
// Succeed if already enabled.
|
||||
R_SUCCEED_IF(m_buffer_sharing_enabled);
|
||||
|
||||
// Ensure we can access shared layers.
|
||||
R_UNLESS(m_manager_display_service != nullptr, VI::ResultOperationFailed);
|
||||
R_UNLESS(m_applet_id != AppletId::Application, VI::ResultPermissionDenied);
|
||||
|
||||
// Create the shared layer.
|
||||
u64 display_id;
|
||||
R_TRY(m_display_service->OpenDisplay(&display_id, VI::DisplayName{"Default"}));
|
||||
R_TRY(m_manager_display_service->CreateSharedLayerSession(m_process, &m_system_shared_buffer_id,
|
||||
&m_system_shared_layer_id, display_id,
|
||||
m_blending_enabled));
|
||||
|
||||
// We succeeded, so set up remaining state.
|
||||
m_buffer_sharing_enabled = true;
|
||||
m_manager_display_service->SetLayerVisibility(m_visible, m_system_shared_layer_id);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result DisplayLayerManager::GetSystemSharedLayerHandle(u64* out_system_shared_buffer_id,
|
||||
u64* out_system_shared_layer_id) {
|
||||
R_TRY(this->IsSystemBufferSharingEnabled());
|
||||
|
||||
*out_system_shared_buffer_id = m_system_shared_buffer_id;
|
||||
*out_system_shared_layer_id = m_system_shared_layer_id;
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void DisplayLayerManager::SetWindowVisibility(bool visible) {
|
||||
if (m_visible == visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_visible = visible;
|
||||
|
||||
if (m_manager_display_service) {
|
||||
if (m_system_shared_layer_id) {
|
||||
m_manager_display_service->SetLayerVisibility(m_visible, m_system_shared_layer_id);
|
||||
}
|
||||
|
||||
for (const auto layer_id : m_managed_display_layers) {
|
||||
m_manager_display_service->SetLayerVisibility(m_visible, layer_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool DisplayLayerManager::GetWindowVisibility() const {
|
||||
return m_visible;
|
||||
}
|
||||
|
||||
Result DisplayLayerManager::WriteAppletCaptureBuffer(bool* out_was_written,
|
||||
s32* out_fbshare_layer_index) {
|
||||
R_UNLESS(m_buffer_sharing_enabled, VI::ResultPermissionDenied);
|
||||
R_RETURN(m_display_service->GetContainer()->GetSharedBufferManager()->WriteAppletCaptureBuffer(
|
||||
out_was_written, out_fbshare_layer_index));
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
||||
62
src/core/hle/service/am/display_layer_manager.h
Normal file
62
src/core/hle/service/am/display_layer_manager.h
Normal file
@@ -0,0 +1,62 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/am/am_types.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
class KProcess;
|
||||
}
|
||||
|
||||
namespace Service::VI {
|
||||
class IApplicationDisplayService;
|
||||
class IManagerDisplayService;
|
||||
} // namespace Service::VI
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class DisplayLayerManager {
|
||||
public:
|
||||
explicit DisplayLayerManager();
|
||||
~DisplayLayerManager();
|
||||
|
||||
void Initialize(Core::System& system, Kernel::KProcess* process, AppletId applet_id,
|
||||
LibraryAppletMode mode);
|
||||
void Finalize();
|
||||
|
||||
Result CreateManagedDisplayLayer(u64* out_layer_id);
|
||||
Result CreateManagedDisplaySeparableLayer(u64* out_layer_id, u64* out_recording_layer_id);
|
||||
|
||||
Result IsSystemBufferSharingEnabled();
|
||||
Result GetSystemSharedLayerHandle(u64* out_system_shared_buffer_id,
|
||||
u64* out_system_shared_layer_id);
|
||||
|
||||
void SetWindowVisibility(bool visible);
|
||||
bool GetWindowVisibility() const;
|
||||
|
||||
Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_fbshare_layer_index);
|
||||
|
||||
private:
|
||||
Kernel::KProcess* m_process{};
|
||||
std::shared_ptr<VI::IApplicationDisplayService> m_display_service{};
|
||||
std::shared_ptr<VI::IManagerDisplayService> m_manager_display_service{};
|
||||
std::set<u64> m_managed_display_layers{};
|
||||
std::set<u64> m_managed_display_recording_layers{};
|
||||
u64 m_system_shared_buffer_id{};
|
||||
u64 m_system_shared_layer_id{};
|
||||
AppletId m_applet_id{};
|
||||
bool m_buffer_sharing_enabled{};
|
||||
bool m_blending_enabled{};
|
||||
bool m_visible{true};
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "core/hle/service/am/frontend/applet_web_browser.h"
|
||||
#include "core/hle/service/am/service/storage.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/hle/service/ns/iplatform_service_manager.h"
|
||||
#include "core/hle/service/ns/platform_service_manager.h"
|
||||
#include "core/loader/loader.h"
|
||||
|
||||
namespace Service::AM::Frontend {
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/am/managed_layer_holder.h"
|
||||
#include "core/hle/service/nvnflinger/nvnflinger.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
ManagedLayerHolder::ManagedLayerHolder() = default;
|
||||
ManagedLayerHolder::~ManagedLayerHolder() {
|
||||
if (!m_nvnflinger) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& layer : m_managed_display_layers) {
|
||||
m_nvnflinger->DestroyLayer(layer);
|
||||
}
|
||||
|
||||
for (const auto& layer : m_managed_display_recording_layers) {
|
||||
m_nvnflinger->DestroyLayer(layer);
|
||||
}
|
||||
|
||||
m_nvnflinger = nullptr;
|
||||
}
|
||||
|
||||
void ManagedLayerHolder::Initialize(Nvnflinger::Nvnflinger* nvnflinger) {
|
||||
m_nvnflinger = nvnflinger;
|
||||
}
|
||||
|
||||
void ManagedLayerHolder::CreateManagedDisplayLayer(u64* out_layer) {
|
||||
// TODO(Subv): Find out how AM determines the display to use, for now just
|
||||
// create the layer in the Default display.
|
||||
const auto display_id = m_nvnflinger->OpenDisplay("Default");
|
||||
const auto layer_id = m_nvnflinger->CreateLayer(*display_id);
|
||||
|
||||
m_managed_display_layers.emplace(*layer_id);
|
||||
|
||||
*out_layer = *layer_id;
|
||||
}
|
||||
|
||||
void ManagedLayerHolder::CreateManagedDisplaySeparableLayer(u64* out_layer,
|
||||
u64* out_recording_layer) {
|
||||
// TODO(Subv): Find out how AM determines the display to use, for now just
|
||||
// create the layer in the Default display.
|
||||
// This calls nn::vi::CreateRecordingLayer() which creates another layer.
|
||||
// Currently we do not support more than 1 layer per display, output 1 layer id for now.
|
||||
// Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse
|
||||
// side effects.
|
||||
// TODO: Support multiple layers
|
||||
const auto display_id = m_nvnflinger->OpenDisplay("Default");
|
||||
const auto layer_id = m_nvnflinger->CreateLayer(*display_id);
|
||||
|
||||
m_managed_display_layers.emplace(*layer_id);
|
||||
|
||||
*out_layer = *layer_id;
|
||||
*out_recording_layer = 0;
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
||||
@@ -1,32 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Service::Nvnflinger {
|
||||
class Nvnflinger;
|
||||
}
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class ManagedLayerHolder {
|
||||
public:
|
||||
ManagedLayerHolder();
|
||||
~ManagedLayerHolder();
|
||||
|
||||
void Initialize(Nvnflinger::Nvnflinger* nvnflinger);
|
||||
void CreateManagedDisplayLayer(u64* out_layer);
|
||||
void CreateManagedDisplaySeparableLayer(u64* out_layer, u64* out_recording_layer);
|
||||
|
||||
private:
|
||||
Nvnflinger::Nvnflinger* m_nvnflinger{};
|
||||
std::set<u64> m_managed_display_layers{};
|
||||
std::set<u64> m_managed_display_recording_layers{};
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
||||
@@ -68,7 +68,9 @@ bool Process::Initialize(u64 program_id, u8 minimum_key_generation, u8 maximum_k
|
||||
Kernel::KProcess::Register(m_system.Kernel(), process);
|
||||
|
||||
// On exit, ensure we free the additional reference to the process.
|
||||
SCOPE_EXIT({ process->Close(); });
|
||||
SCOPE_EXIT {
|
||||
process->Close();
|
||||
};
|
||||
|
||||
// Insert process modules into memory.
|
||||
const auto [load_result, load_parameters] = app_loader->Load(*process, m_system);
|
||||
|
||||
@@ -10,9 +10,8 @@
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
IAllSystemAppletProxiesService::IAllSystemAppletProxiesService(Core::System& system_,
|
||||
Nvnflinger::Nvnflinger& nvnflinger)
|
||||
: ServiceFramework{system_, "appletAE"}, m_nvnflinger{nvnflinger} {
|
||||
IAllSystemAppletProxiesService::IAllSystemAppletProxiesService(Core::System& system_)
|
||||
: ServiceFramework{system_, "appletAE"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{100, D<&IAllSystemAppletProxiesService::OpenSystemAppletProxy>, "OpenSystemAppletProxy"},
|
||||
@@ -37,8 +36,8 @@ Result IAllSystemAppletProxiesService::OpenSystemAppletProxy(
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
if (const auto applet = this->GetAppletFromProcessId(pid); applet) {
|
||||
*out_system_applet_proxy = std::make_shared<ISystemAppletProxy>(
|
||||
system, applet, process_handle.Get(), m_nvnflinger);
|
||||
*out_system_applet_proxy =
|
||||
std::make_shared<ISystemAppletProxy>(system, applet, process_handle.Get());
|
||||
R_SUCCEED();
|
||||
} else {
|
||||
UNIMPLEMENTED();
|
||||
@@ -53,8 +52,8 @@ Result IAllSystemAppletProxiesService::OpenLibraryAppletProxy(
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
if (const auto applet = this->GetAppletFromProcessId(pid); applet) {
|
||||
*out_library_applet_proxy = std::make_shared<ILibraryAppletProxy>(
|
||||
system, applet, process_handle.Get(), m_nvnflinger);
|
||||
*out_library_applet_proxy =
|
||||
std::make_shared<ILibraryAppletProxy>(system, applet, process_handle.Get());
|
||||
R_SUCCEED();
|
||||
} else {
|
||||
UNIMPLEMENTED();
|
||||
|
||||
@@ -8,10 +8,6 @@
|
||||
|
||||
namespace Service {
|
||||
|
||||
namespace Nvnflinger {
|
||||
class Nvnflinger;
|
||||
}
|
||||
|
||||
namespace AM {
|
||||
|
||||
struct Applet;
|
||||
@@ -22,8 +18,7 @@ class ISystemAppletProxy;
|
||||
class IAllSystemAppletProxiesService final
|
||||
: public ServiceFramework<IAllSystemAppletProxiesService> {
|
||||
public:
|
||||
explicit IAllSystemAppletProxiesService(Core::System& system_,
|
||||
Nvnflinger::Nvnflinger& nvnflinger);
|
||||
explicit IAllSystemAppletProxiesService(Core::System& system_);
|
||||
~IAllSystemAppletProxiesService() override;
|
||||
|
||||
private:
|
||||
@@ -40,7 +35,6 @@ private:
|
||||
|
||||
private:
|
||||
std::shared_ptr<Applet> GetAppletFromProcessId(ProcessId pid);
|
||||
Nvnflinger::Nvnflinger& m_nvnflinger;
|
||||
};
|
||||
|
||||
} // namespace AM
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/hle/service/filesystem/save_data_controller.h"
|
||||
#include "core/hle/service/glue/glue_manager.h"
|
||||
#include "core/hle/service/ns/ns.h"
|
||||
#include "core/hle/service/ns/application_manager_interface.h"
|
||||
#include "core/hle/service/ns/service_getter_interface.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
|
||||
namespace Service::AM {
|
||||
@@ -163,11 +164,13 @@ Result IApplicationFunctions::GetDesiredLanguage(Out<u64> out_language_code) {
|
||||
|
||||
// Call IApplicationManagerInterface implementation.
|
||||
auto& service_manager = system.ServiceManager();
|
||||
auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2");
|
||||
auto app_man = ns_am2->GetApplicationManagerInterface();
|
||||
auto ns_am2 = service_manager.GetService<NS::IServiceGetterInterface>("ns:am2");
|
||||
|
||||
std::shared_ptr<NS::IApplicationManagerInterface> app_man;
|
||||
R_TRY(ns_am2->GetApplicationManagerInterface(&app_man));
|
||||
|
||||
// Get desired application language
|
||||
u8 desired_language{};
|
||||
NS::ApplicationLanguage desired_language{};
|
||||
R_TRY(app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages));
|
||||
|
||||
// Convert to settings language code.
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
namespace Service::AM {
|
||||
|
||||
IApplicationProxy::IApplicationProxy(Core::System& system_, std::shared_ptr<Applet> applet,
|
||||
Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger)
|
||||
: ServiceFramework{system_, "IApplicationProxy"},
|
||||
m_nvnflinger{nvnflinger}, m_process{process}, m_applet{std::move(applet)} {
|
||||
Kernel::KProcess* process)
|
||||
: ServiceFramework{system_, "IApplicationProxy"}, m_process{process}, m_applet{
|
||||
std::move(applet)} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, D<&IApplicationProxy::GetCommonStateGetter>, "GetCommonStateGetter"},
|
||||
@@ -77,8 +77,7 @@ Result IApplicationProxy::GetWindowController(
|
||||
Result IApplicationProxy::GetSelfController(
|
||||
Out<SharedPointer<ISelfController>> out_self_controller) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_self_controller =
|
||||
std::make_shared<ISelfController>(system, m_applet, m_process, m_nvnflinger);
|
||||
*out_self_controller = std::make_shared<ISelfController>(system, m_applet, m_process);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ class IWindowController;
|
||||
class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {
|
||||
public:
|
||||
explicit IApplicationProxy(Core::System& system_, std::shared_ptr<Applet> applet,
|
||||
Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger);
|
||||
Kernel::KProcess* process);
|
||||
~IApplicationProxy();
|
||||
|
||||
private:
|
||||
@@ -40,7 +40,6 @@ private:
|
||||
Out<SharedPointer<IApplicationFunctions>> out_application_functions);
|
||||
|
||||
private:
|
||||
Nvnflinger::Nvnflinger& m_nvnflinger;
|
||||
Kernel::KProcess* const m_process;
|
||||
const std::shared_ptr<Applet> m_applet;
|
||||
};
|
||||
|
||||
@@ -10,9 +10,8 @@
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
IApplicationProxyService::IApplicationProxyService(Core::System& system_,
|
||||
Nvnflinger::Nvnflinger& nvnflinger)
|
||||
: ServiceFramework{system_, "appletOE"}, m_nvnflinger{nvnflinger} {
|
||||
IApplicationProxyService::IApplicationProxyService(Core::System& system_)
|
||||
: ServiceFramework{system_, "appletOE"} {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, D<&IApplicationProxyService::OpenApplicationProxy>, "OpenApplicationProxy"},
|
||||
};
|
||||
@@ -28,7 +27,7 @@ Result IApplicationProxyService::OpenApplicationProxy(
|
||||
|
||||
if (const auto applet = this->GetAppletFromProcessId(pid)) {
|
||||
*out_application_proxy =
|
||||
std::make_shared<IApplicationProxy>(system, applet, process_handle.Get(), m_nvnflinger);
|
||||
std::make_shared<IApplicationProxy>(system, applet, process_handle.Get());
|
||||
R_SUCCEED();
|
||||
} else {
|
||||
UNIMPLEMENTED();
|
||||
|
||||
@@ -8,10 +8,6 @@
|
||||
|
||||
namespace Service {
|
||||
|
||||
namespace Nvnflinger {
|
||||
class Nvnflinger;
|
||||
}
|
||||
|
||||
namespace AM {
|
||||
|
||||
struct Applet;
|
||||
@@ -19,7 +15,7 @@ class IApplicationProxy;
|
||||
|
||||
class IApplicationProxyService final : public ServiceFramework<IApplicationProxyService> {
|
||||
public:
|
||||
explicit IApplicationProxyService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger);
|
||||
explicit IApplicationProxyService(Core::System& system_);
|
||||
~IApplicationProxyService() override;
|
||||
|
||||
private:
|
||||
@@ -28,7 +24,6 @@ private:
|
||||
|
||||
private:
|
||||
std::shared_ptr<Applet> GetAppletFromProcessId(ProcessId pid);
|
||||
Nvnflinger::Nvnflinger& m_nvnflinger;
|
||||
};
|
||||
|
||||
} // namespace AM
|
||||
|
||||
@@ -69,7 +69,7 @@ Result IDisplayController::ClearCaptureBuffer(bool unknown0, s32 fbshare_layer_i
|
||||
Result IDisplayController::AcquireLastForegroundCaptureSharedBuffer(
|
||||
Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
R_RETURN(applet->system_buffer_manager.WriteAppletCaptureBuffer(out_was_written,
|
||||
R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(out_was_written,
|
||||
out_fbshare_layer_index));
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ Result IDisplayController::ReleaseLastForegroundCaptureSharedBuffer() {
|
||||
Result IDisplayController::AcquireCallerAppletCaptureSharedBuffer(
|
||||
Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
R_RETURN(applet->system_buffer_manager.WriteAppletCaptureBuffer(out_was_written,
|
||||
R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(out_was_written,
|
||||
out_fbshare_layer_index));
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ Result IDisplayController::ReleaseCallerAppletCaptureSharedBuffer() {
|
||||
Result IDisplayController::AcquireLastApplicationCaptureSharedBuffer(
|
||||
Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
R_RETURN(applet->system_buffer_manager.WriteAppletCaptureBuffer(out_was_written,
|
||||
R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(out_was_written,
|
||||
out_fbshare_layer_index));
|
||||
}
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(Core::System& system,
|
||||
case LibraryAppletMode::AllForegroundInitiallyHidden:
|
||||
applet->hid_registration.EnableAppletToGetInput(false);
|
||||
applet->focus_state = FocusState::NotInFocus;
|
||||
applet->system_buffer_manager.SetWindowVisibility(false);
|
||||
applet->display_layer_manager.SetWindowVisibility(false);
|
||||
applet->message_queue.PushMessage(AppletMessage::ChangeIntoBackground);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -19,10 +19,9 @@
|
||||
namespace Service::AM {
|
||||
|
||||
ILibraryAppletProxy::ILibraryAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet,
|
||||
Kernel::KProcess* process,
|
||||
Nvnflinger::Nvnflinger& nvnflinger)
|
||||
: ServiceFramework{system_, "ILibraryAppletProxy"},
|
||||
m_nvnflinger{nvnflinger}, m_process{process}, m_applet{std::move(applet)} {
|
||||
Kernel::KProcess* process)
|
||||
: ServiceFramework{system_, "ILibraryAppletProxy"}, m_process{process}, m_applet{
|
||||
std::move(applet)} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, D<&ILibraryAppletProxy::GetCommonStateGetter>, "GetCommonStateGetter"},
|
||||
@@ -83,8 +82,7 @@ Result ILibraryAppletProxy::GetWindowController(
|
||||
Result ILibraryAppletProxy::GetSelfController(
|
||||
Out<SharedPointer<ISelfController>> out_self_controller) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_self_controller =
|
||||
std::make_shared<ISelfController>(system, m_applet, m_process, m_nvnflinger);
|
||||
*out_self_controller = std::make_shared<ISelfController>(system, m_applet, m_process);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ class IWindowController;
|
||||
class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> {
|
||||
public:
|
||||
explicit ILibraryAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet,
|
||||
Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger);
|
||||
Kernel::KProcess* process);
|
||||
~ILibraryAppletProxy();
|
||||
|
||||
private:
|
||||
@@ -47,7 +47,6 @@ private:
|
||||
Result GetGlobalStateController(
|
||||
Out<SharedPointer<IGlobalStateController>> out_global_state_controller);
|
||||
|
||||
Nvnflinger::Nvnflinger& m_nvnflinger;
|
||||
Kernel::KProcess* const m_process;
|
||||
const std::shared_ptr<Applet> m_applet;
|
||||
};
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
#include "core/hle/service/cmif_serialization.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/hle/service/glue/glue_manager.h"
|
||||
#include "core/hle/service/ns/ns.h"
|
||||
#include "core/hle/service/ns/application_manager_interface.h"
|
||||
#include "core/hle/service/ns/service_getter_interface.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
|
||||
namespace Service::AM {
|
||||
@@ -256,11 +257,13 @@ Result ILibraryAppletSelfAccessor::GetMainAppletApplicationDesiredLanguage(
|
||||
|
||||
// Call IApplicationManagerInterface implementation.
|
||||
auto& service_manager = system.ServiceManager();
|
||||
auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2");
|
||||
auto app_man = ns_am2->GetApplicationManagerInterface();
|
||||
auto ns_am2 = service_manager.GetService<NS::IServiceGetterInterface>("ns:am2");
|
||||
|
||||
std::shared_ptr<NS::IApplicationManagerInterface> app_man;
|
||||
R_TRY(ns_am2->GetApplicationManagerInterface(&app_man));
|
||||
|
||||
// Get desired application language
|
||||
u8 desired_language{};
|
||||
NS::ApplicationLanguage desired_language{};
|
||||
R_TRY(app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages));
|
||||
|
||||
// Convert to settings language code.
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
namespace Service::AM {
|
||||
|
||||
ISelfController::ISelfController(Core::System& system_, std::shared_ptr<Applet> applet,
|
||||
Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger)
|
||||
: ServiceFramework{system_, "ISelfController"},
|
||||
m_nvnflinger{nvnflinger}, m_process{process}, m_applet{std::move(applet)} {
|
||||
Kernel::KProcess* process)
|
||||
: ServiceFramework{system_, "ISelfController"}, m_process{process}, m_applet{
|
||||
std::move(applet)} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, D<&ISelfController::Exit>, "Exit"},
|
||||
@@ -72,9 +72,16 @@ ISelfController::ISelfController(Core::System& system_, std::shared_ptr<Applet>
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
|
||||
std::scoped_lock lk{m_applet->lock};
|
||||
m_applet->display_layer_manager.Initialize(system, m_process, m_applet->applet_id,
|
||||
m_applet->library_applet_mode);
|
||||
}
|
||||
|
||||
ISelfController::~ISelfController() = default;
|
||||
ISelfController::~ISelfController() {
|
||||
std::scoped_lock lk{m_applet->lock};
|
||||
m_applet->display_layer_manager.Finalize();
|
||||
}
|
||||
|
||||
Result ISelfController::Exit() {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
@@ -212,48 +219,42 @@ Result ISelfController::SetAlbumImageOrientation(
|
||||
|
||||
Result ISelfController::IsSystemBufferSharingEnabled() {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
R_SUCCEED_IF(m_applet->system_buffer_manager.Initialize(
|
||||
&m_nvnflinger, m_process, m_applet->applet_id, m_applet->library_applet_mode));
|
||||
R_THROW(VI::ResultOperationFailed);
|
||||
|
||||
std::scoped_lock lk{m_applet->lock};
|
||||
R_RETURN(m_applet->display_layer_manager.IsSystemBufferSharingEnabled());
|
||||
}
|
||||
|
||||
Result ISelfController::GetSystemSharedBufferHandle(Out<u64> out_buffer_id) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
R_TRY(this->IsSystemBufferSharingEnabled());
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
u64 layer_id;
|
||||
m_applet->system_buffer_manager.GetSystemSharedLayerHandle(out_buffer_id, &layer_id);
|
||||
R_SUCCEED();
|
||||
|
||||
std::scoped_lock lk{m_applet->lock};
|
||||
R_RETURN(m_applet->display_layer_manager.GetSystemSharedLayerHandle(out_buffer_id, &layer_id));
|
||||
}
|
||||
|
||||
Result ISelfController::GetSystemSharedLayerHandle(Out<u64> out_buffer_id, Out<u64> out_layer_id) {
|
||||
LOG_INFO(Service_AM, "(STUBBED) called");
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
R_TRY(this->IsSystemBufferSharingEnabled());
|
||||
|
||||
m_applet->system_buffer_manager.GetSystemSharedLayerHandle(out_buffer_id, out_layer_id);
|
||||
R_SUCCEED();
|
||||
std::scoped_lock lk{m_applet->lock};
|
||||
R_RETURN(
|
||||
m_applet->display_layer_manager.GetSystemSharedLayerHandle(out_buffer_id, out_layer_id));
|
||||
}
|
||||
|
||||
Result ISelfController::CreateManagedDisplayLayer(Out<u64> out_layer_id) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
m_applet->managed_layer_holder.Initialize(&m_nvnflinger);
|
||||
m_applet->managed_layer_holder.CreateManagedDisplayLayer(out_layer_id);
|
||||
|
||||
R_SUCCEED();
|
||||
std::scoped_lock lk{m_applet->lock};
|
||||
R_RETURN(m_applet->display_layer_manager.CreateManagedDisplayLayer(out_layer_id));
|
||||
}
|
||||
|
||||
Result ISelfController::CreateManagedDisplaySeparableLayer(Out<u64> out_layer_id,
|
||||
Out<u64> out_recording_layer_id) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
m_applet->managed_layer_holder.Initialize(&m_nvnflinger);
|
||||
m_applet->managed_layer_holder.CreateManagedDisplaySeparableLayer(out_layer_id,
|
||||
out_recording_layer_id);
|
||||
|
||||
R_SUCCEED();
|
||||
std::scoped_lock lk{m_applet->lock};
|
||||
R_RETURN(m_applet->display_layer_manager.CreateManagedDisplaySeparableLayer(
|
||||
out_layer_id, out_recording_layer_id));
|
||||
}
|
||||
|
||||
Result ISelfController::SetHandlesRequestToDisplay(bool enable) {
|
||||
|
||||
@@ -23,7 +23,7 @@ struct Applet;
|
||||
class ISelfController final : public ServiceFramework<ISelfController> {
|
||||
public:
|
||||
explicit ISelfController(Core::System& system_, std::shared_ptr<Applet> applet,
|
||||
Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger);
|
||||
Kernel::KProcess* process);
|
||||
~ISelfController() override;
|
||||
|
||||
private:
|
||||
@@ -64,7 +64,6 @@ private:
|
||||
Result SaveCurrentScreenshot(Capture::AlbumReportOption album_report_option);
|
||||
Result SetRecordVolumeMuted(bool muted);
|
||||
|
||||
Nvnflinger::Nvnflinger& m_nvnflinger;
|
||||
Kernel::KProcess* const m_process;
|
||||
const std::shared_ptr<Applet> m_applet;
|
||||
};
|
||||
|
||||
@@ -19,10 +19,9 @@
|
||||
namespace Service::AM {
|
||||
|
||||
ISystemAppletProxy::ISystemAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet,
|
||||
Kernel::KProcess* process,
|
||||
Nvnflinger::Nvnflinger& nvnflinger)
|
||||
: ServiceFramework{system_, "ISystemAppletProxy"},
|
||||
m_nvnflinger{nvnflinger}, m_process{process}, m_applet{std::move(applet)} {
|
||||
Kernel::KProcess* process)
|
||||
: ServiceFramework{system_, "ISystemAppletProxy"}, m_process{process}, m_applet{
|
||||
std::move(applet)} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, D<&ISystemAppletProxy::GetCommonStateGetter>, "GetCommonStateGetter"},
|
||||
@@ -83,8 +82,7 @@ Result ISystemAppletProxy::GetWindowController(
|
||||
Result ISystemAppletProxy::GetSelfController(
|
||||
Out<SharedPointer<ISelfController>> out_self_controller) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_self_controller =
|
||||
std::make_shared<ISelfController>(system, m_applet, m_process, m_nvnflinger);
|
||||
*out_self_controller = std::make_shared<ISelfController>(system, m_applet, m_process);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ class IWindowController;
|
||||
class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> {
|
||||
public:
|
||||
explicit ISystemAppletProxy(Core::System& system, std::shared_ptr<Applet> applet,
|
||||
Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger);
|
||||
Kernel::KProcess* process);
|
||||
~ISystemAppletProxy();
|
||||
|
||||
private:
|
||||
@@ -46,7 +46,6 @@ private:
|
||||
Result GetGlobalStateController(
|
||||
Out<SharedPointer<IGlobalStateController>> out_global_state_controller);
|
||||
|
||||
Nvnflinger::Nvnflinger& m_nvnflinger;
|
||||
Kernel::KProcess* const m_process;
|
||||
const std::shared_ptr<Applet> m_applet;
|
||||
};
|
||||
|
||||
@@ -63,7 +63,7 @@ Result IWindowController::RejectToChangeIntoBackground() {
|
||||
}
|
||||
|
||||
Result IWindowController::SetAppletWindowVisibility(bool visible) {
|
||||
m_applet->system_buffer_manager.SetWindowVisibility(visible);
|
||||
m_applet->display_layer_manager.SetWindowVisibility(visible);
|
||||
m_applet->hid_registration.EnableAppletToGetInput(visible);
|
||||
|
||||
if (visible) {
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/am/system_buffer_manager.h"
|
||||
#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
|
||||
#include "core/hle/service/nvnflinger/nvnflinger.h"
|
||||
#include "core/hle/service/vi/vi_results.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
SystemBufferManager::SystemBufferManager() = default;
|
||||
|
||||
SystemBufferManager::~SystemBufferManager() {
|
||||
if (!m_nvnflinger) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clean up shared layers.
|
||||
if (m_buffer_sharing_enabled) {
|
||||
m_nvnflinger->GetSystemBufferManager().Finalize(m_process);
|
||||
}
|
||||
}
|
||||
|
||||
bool SystemBufferManager::Initialize(Nvnflinger::Nvnflinger* nvnflinger, Kernel::KProcess* process,
|
||||
AppletId applet_id, LibraryAppletMode mode) {
|
||||
if (m_nvnflinger) {
|
||||
return m_buffer_sharing_enabled;
|
||||
}
|
||||
|
||||
m_process = process;
|
||||
m_nvnflinger = nvnflinger;
|
||||
m_buffer_sharing_enabled = false;
|
||||
m_system_shared_buffer_id = 0;
|
||||
m_system_shared_layer_id = 0;
|
||||
|
||||
if (applet_id <= AppletId::Application) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Nvnflinger::LayerBlending blending = Nvnflinger::LayerBlending::None;
|
||||
if (mode == LibraryAppletMode::PartialForeground ||
|
||||
mode == LibraryAppletMode::PartialForegroundIndirectDisplay) {
|
||||
blending = Nvnflinger::LayerBlending::Coverage;
|
||||
}
|
||||
|
||||
const auto display_id = m_nvnflinger->OpenDisplay("Default").value();
|
||||
const auto res = m_nvnflinger->GetSystemBufferManager().Initialize(
|
||||
m_process, &m_system_shared_buffer_id, &m_system_shared_layer_id, display_id, blending);
|
||||
|
||||
if (res.IsSuccess()) {
|
||||
m_buffer_sharing_enabled = true;
|
||||
m_nvnflinger->SetLayerVisibility(m_system_shared_layer_id, m_visible);
|
||||
}
|
||||
|
||||
return m_buffer_sharing_enabled;
|
||||
}
|
||||
|
||||
void SystemBufferManager::SetWindowVisibility(bool visible) {
|
||||
if (m_visible == visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_visible = visible;
|
||||
|
||||
if (m_nvnflinger) {
|
||||
m_nvnflinger->SetLayerVisibility(m_system_shared_layer_id, m_visible);
|
||||
}
|
||||
}
|
||||
|
||||
Result SystemBufferManager::WriteAppletCaptureBuffer(bool* out_was_written,
|
||||
s32* out_fbshare_layer_index) {
|
||||
if (!m_buffer_sharing_enabled) {
|
||||
return VI::ResultPermissionDenied;
|
||||
}
|
||||
|
||||
return m_nvnflinger->GetSystemBufferManager().WriteAppletCaptureBuffer(out_was_written,
|
||||
out_fbshare_layer_index);
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
||||
@@ -1,52 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
#include "core/hle/service/am/am_types.h"
|
||||
|
||||
namespace Kernel {
|
||||
class KProcess;
|
||||
}
|
||||
|
||||
namespace Service::Nvnflinger {
|
||||
class Nvnflinger;
|
||||
}
|
||||
|
||||
union Result;
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class SystemBufferManager {
|
||||
public:
|
||||
SystemBufferManager();
|
||||
~SystemBufferManager();
|
||||
|
||||
bool Initialize(Nvnflinger::Nvnflinger* flinger, Kernel::KProcess* process, AppletId applet_id,
|
||||
LibraryAppletMode mode);
|
||||
|
||||
void GetSystemSharedLayerHandle(u64* out_system_shared_buffer_id,
|
||||
u64* out_system_shared_layer_id) {
|
||||
*out_system_shared_buffer_id = m_system_shared_buffer_id;
|
||||
*out_system_shared_layer_id = m_system_shared_layer_id;
|
||||
}
|
||||
|
||||
void SetWindowVisibility(bool visible);
|
||||
|
||||
Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_fbshare_layer_index);
|
||||
|
||||
private:
|
||||
Kernel::KProcess* m_process{};
|
||||
Nvnflinger::Nvnflinger* m_nvnflinger{};
|
||||
bool m_buffer_sharing_enabled{};
|
||||
bool m_visible{true};
|
||||
u64 m_system_shared_buffer_id{};
|
||||
u64 m_system_shared_layer_id{};
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -3,10 +3,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Service::SM {
|
||||
class ServiceManager;
|
||||
}
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
};
|
||||
|
||||
33
src/core/hle/service/btm/btm_debug.cpp
Normal file
33
src/core/hle/service/btm/btm_debug.cpp
Normal file
@@ -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
|
||||
21
src/core/hle/service/btm/btm_debug.h
Normal file
21
src/core/hle/service/btm/btm_debug.h
Normal file
@@ -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
|
||||
31
src/core/hle/service/btm/btm_system.cpp
Normal file
31
src/core/hle/service/btm/btm_system.cpp
Normal file
@@ -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
|
||||
25
src/core/hle/service/btm/btm_system.h
Normal file
25
src/core/hle/service/btm/btm_system.h
Normal file
@@ -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
|
||||
127
src/core/hle/service/btm/btm_system_core.cpp
Normal file
127
src/core/hle/service/btm/btm_system_core.cpp
Normal file
@@ -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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user