Compare commits
10 Commits
android-26
...
android-25
Author | SHA1 | Date | |
---|---|---|---|
53eb86513d | |||
e85a2f9f75 | |||
89dd56ae42 | |||
cdf60ba092 | |||
9cc88db6d0 | |||
764f3a0c8c | |||
378fcc2cd4 | |||
5beb4449e0 | |||
12f8119826 | |||
0d129b8c31 |
16
README.md
16
README.md
@ -1,14 +1,14 @@
|
|||||||
| Pull Request | Commit | Title | Author | Merged? |
|
| 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 |
|
| [10529](https://github.com/yuzu-emu/yuzu//pull/10529) | [`368bf2211`](https://github.com/yuzu-emu/yuzu//pull/10529/files) | caches: make critical reclamation less eager and possible in more cases | [liamwhite](https://github.com/liamwhite/) | Yes |
|
||||||
|
| [12461](https://github.com/yuzu-emu/yuzu//pull/12461) | [`acc26667b`](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 |
|
| [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 |
|
||||||
| [13073](https://github.com/yuzu-emu/yuzu//pull/13073) | [`b5a17b501`](https://github.com/yuzu-emu/yuzu//pull/13073/files) | fsp: Migrate remaining interfaces to 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 |
|
||||||
| [13081](https://github.com/yuzu-emu/yuzu//pull/13081) | [`197c4d325`](https://github.com/yuzu-emu/yuzu//pull/13081/files) | aoc: Migrate to use cmif serialization | [FearlessTobi](https://github.com/FearlessTobi/) | Yes |
|
| [13006](https://github.com/yuzu-emu/yuzu//pull/13006) | [`3067bfd12`](https://github.com/yuzu-emu/yuzu//pull/13006/files) | buffer_cache: use mapped range with large vertex buffer size | [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 |
|
| [13026](https://github.com/yuzu-emu/yuzu//pull/13026) | [`462ea921e`](https://github.com/yuzu-emu/yuzu//pull/13026/files) | shader_recompiler: fix non-const offset for arrayed image types | [liamwhite](https://github.com/liamwhite/) | Yes |
|
||||||
| [13100](https://github.com/yuzu-emu/yuzu//pull/13100) | [`c04567fad`](https://github.com/yuzu-emu/yuzu//pull/13100/files) | audio: move to new ipc | [liamwhite](https://github.com/liamwhite/) | Yes |
|
| [13031](https://github.com/yuzu-emu/yuzu//pull/13031) | [`110969e20`](https://github.com/yuzu-emu/yuzu//pull/13031/files) | service: btm: Migrate service to new IPC | [german77](https://github.com/german77/) | Yes |
|
||||||
| [13115](https://github.com/yuzu-emu/yuzu//pull/13115) | [`89c2fd3d2`](https://github.com/yuzu-emu/yuzu//pull/13115/files) | olsc, pctl: move to new ipc | [liamwhite](https://github.com/liamwhite/) | Yes |
|
| [13035](https://github.com/yuzu-emu/yuzu//pull/13035) | [`940a71422`](https://github.com/yuzu-emu/yuzu//pull/13035/files) | vi: manage resources independently of nvnflinger and refactor | [liamwhite](https://github.com/liamwhite/) | Yes |
|
||||||
| [13116](https://github.com/yuzu-emu/yuzu//pull/13116) | [`54ed837ad`](https://github.com/yuzu-emu/yuzu//pull/13116/files) | android: Flip AB/XY for 8Bitdo controllers | [t895](https://github.com/t895/) | Yes |
|
| [13048](https://github.com/yuzu-emu/yuzu//pull/13048) | [`d45a12826`](https://github.com/yuzu-emu/yuzu//pull/13048/files) | ns: rewrite for new IPC | [liamwhite](https://github.com/liamwhite/) | Yes |
|
||||||
| [13117](https://github.com/yuzu-emu/yuzu//pull/13117) | [`e85466c1a`](https://github.com/yuzu-emu/yuzu//pull/13117/files) | psc: stub overlay notification channel | [liamwhite](https://github.com/liamwhite/) | Yes |
|
|
||||||
|
|
||||||
|
|
||||||
End of merge log. You can find the original README.md below the break.
|
End of merge log. You can find the original README.md below the break.
|
||||||
|
@ -121,7 +121,6 @@ else()
|
|||||||
-Wno-attributes
|
-Wno-attributes
|
||||||
-Wno-invalid-offsetof
|
-Wno-invalid-offsetof
|
||||||
-Wno-unused-parameter
|
-Wno-unused-parameter
|
||||||
-Wno-missing-field-initializers
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (CMAKE_CXX_COMPILER_ID MATCHES Clang) # Clang or AppleClang
|
if (CMAKE_CXX_COMPILER_ID MATCHES Clang) # Clang or AppleClang
|
||||||
|
@ -64,17 +64,17 @@ data class PlayerInput(
|
|||||||
fun hasMapping(): Boolean {
|
fun hasMapping(): Boolean {
|
||||||
var hasMapping = false
|
var hasMapping = false
|
||||||
buttons.forEach {
|
buttons.forEach {
|
||||||
if (it != "[empty]" && it.isNotEmpty()) {
|
if (it != "[empty]") {
|
||||||
hasMapping = true
|
hasMapping = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
analogs.forEach {
|
analogs.forEach {
|
||||||
if (it != "[empty]" && it.isNotEmpty()) {
|
if (it != "[empty]") {
|
||||||
hasMapping = true
|
hasMapping = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
motions.forEach {
|
motions.forEach {
|
||||||
if (it != "[empty]" && it.isNotEmpty()) {
|
if (it != "[empty]") {
|
||||||
hasMapping = true
|
hasMapping = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,7 @@ package org.yuzu.yuzu_emu.features.settings.model
|
|||||||
import org.yuzu.yuzu_emu.utils.NativeConfig
|
import org.yuzu.yuzu_emu.utils.NativeConfig
|
||||||
|
|
||||||
enum class StringSetting(override val key: String) : AbstractStringSetting {
|
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)
|
override fun getString(needsGlobal: Boolean): String = NativeConfig.getString(key, needsGlobal)
|
||||||
|
|
||||||
|
@ -16,7 +16,6 @@ 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.IntSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.LongSetting
|
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.ShortSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
|
|
||||||
import org.yuzu.yuzu_emu.utils.NativeConfig
|
import org.yuzu.yuzu_emu.utils.NativeConfig
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -76,9 +75,6 @@ abstract class SettingsItem(
|
|||||||
get() = NativeLibrary.isRunning() && !setting.global &&
|
get() = NativeLibrary.isRunning() && !setting.global &&
|
||||||
!NativeConfig.isPerGameConfigLoaded()
|
!NativeConfig.isPerGameConfigLoaded()
|
||||||
|
|
||||||
val clearable: Boolean
|
|
||||||
get() = !setting.global && NativeConfig.isPerGameConfigLoaded()
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val TYPE_HEADER = 0
|
const val TYPE_HEADER = 0
|
||||||
const val TYPE_SWITCH = 1
|
const val TYPE_SWITCH = 1
|
||||||
@ -91,7 +87,6 @@ abstract class SettingsItem(
|
|||||||
const val TYPE_INPUT = 8
|
const val TYPE_INPUT = 8
|
||||||
const val TYPE_INT_SINGLE_CHOICE = 9
|
const val TYPE_INT_SINGLE_CHOICE = 9
|
||||||
const val TYPE_INPUT_PROFILE = 10
|
const val TYPE_INPUT_PROFILE = 10
|
||||||
const val TYPE_STRING_INPUT = 11
|
|
||||||
|
|
||||||
const val FASTMEM_COMBINED = "fastmem_combined"
|
const val FASTMEM_COMBINED = "fastmem_combined"
|
||||||
|
|
||||||
@ -110,7 +105,6 @@ abstract class SettingsItem(
|
|||||||
|
|
||||||
// List of all general
|
// List of all general
|
||||||
val settingsItems = HashMap<String, SettingsItem>().apply {
|
val settingsItems = HashMap<String, SettingsItem>().apply {
|
||||||
put(StringInputSetting(StringSetting.DEVICE_NAME, titleId = R.string.device_name))
|
|
||||||
put(
|
put(
|
||||||
SwitchSetting(
|
SwitchSetting(
|
||||||
BooleanSetting.RENDERER_USE_SPEED_LIMIT,
|
BooleanSetting.RENDERER_USE_SPEED_LIMIT,
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
// 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,10 +85,6 @@ class SettingsAdapter(
|
|||||||
InputProfileViewHolder(ListItemSettingBinding.inflate(inflater), this)
|
InputProfileViewHolder(ListItemSettingBinding.inflate(inflater), this)
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsItem.TYPE_STRING_INPUT -> {
|
|
||||||
StringInputViewHolder(ListItemSettingBinding.inflate(inflater), this)
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
HeaderViewHolder(ListItemSettingsHeaderBinding.inflate(inflater), this)
|
HeaderViewHolder(ListItemSettingsHeaderBinding.inflate(inflater), this)
|
||||||
}
|
}
|
||||||
@ -396,15 +392,6 @@ class SettingsAdapter(
|
|||||||
popup.show()
|
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 {
|
fun onLongClick(item: SettingsItem, position: Int): Boolean {
|
||||||
SettingsDialogFragment.newInstance(
|
SettingsDialogFragment.newInstance(
|
||||||
settingsViewModel,
|
settingsViewModel,
|
||||||
|
@ -14,7 +14,6 @@ import androidx.fragment.app.activityViewModels
|
|||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.slider.Slider
|
import com.google.android.material.slider.Slider
|
||||||
import org.yuzu.yuzu_emu.R
|
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.databinding.DialogSliderBinding
|
||||||
import org.yuzu.yuzu_emu.features.input.NativeInput
|
import org.yuzu.yuzu_emu.features.input.NativeInput
|
||||||
import org.yuzu.yuzu_emu.features.input.model.AnalogDirection
|
import org.yuzu.yuzu_emu.features.input.model.AnalogDirection
|
||||||
@ -24,7 +23,6 @@ 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.SettingsItem
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting
|
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.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.features.settings.model.view.StringSingleChoiceSetting
|
||||||
import org.yuzu.yuzu_emu.utils.ParamPackage
|
import org.yuzu.yuzu_emu.utils.ParamPackage
|
||||||
import org.yuzu.yuzu_emu.utils.collect
|
import org.yuzu.yuzu_emu.utils.collect
|
||||||
@ -39,7 +37,6 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
|
|||||||
private val settingsViewModel: SettingsViewModel by activityViewModels()
|
private val settingsViewModel: SettingsViewModel by activityViewModels()
|
||||||
|
|
||||||
private lateinit var sliderBinding: DialogSliderBinding
|
private lateinit var sliderBinding: DialogSliderBinding
|
||||||
private lateinit var stringInputBinding: DialogEditTextBinding
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@ -134,18 +131,6 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
|
|||||||
.create()
|
.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 -> {
|
SettingsItem.TYPE_STRING_SINGLE_CHOICE -> {
|
||||||
val item = settingsViewModel.clickedItem as StringSingleChoiceSetting
|
val item = settingsViewModel.clickedItem as StringSingleChoiceSetting
|
||||||
MaterialAlertDialogBuilder(requireContext())
|
MaterialAlertDialogBuilder(requireContext())
|
||||||
@ -173,7 +158,6 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
|
|||||||
): View? {
|
): View? {
|
||||||
return when (type) {
|
return when (type) {
|
||||||
SettingsItem.TYPE_SLIDER -> sliderBinding.root
|
SettingsItem.TYPE_SLIDER -> sliderBinding.root
|
||||||
SettingsItem.TYPE_STRING_INPUT -> stringInputBinding.root
|
|
||||||
else -> super.onCreateView(inflater, container, savedInstanceState)
|
else -> super.onCreateView(inflater, container, savedInstanceState)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -216,13 +200,6 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
|
|||||||
val sliderSetting = settingsViewModel.clickedItem as SliderSetting
|
val sliderSetting = settingsViewModel.clickedItem as SliderSetting
|
||||||
sliderSetting.setSelectedValue(settingsViewModel.sliderProgress.value)
|
sliderSetting.setSelectedValue(settingsViewModel.sliderProgress.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
is StringInputSetting -> {
|
|
||||||
val stringInputSetting = settingsViewModel.clickedItem as StringInputSetting
|
|
||||||
stringInputSetting.setSelectedValue(
|
|
||||||
(stringInputBinding.editText.text ?: "").toString()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
closeDialog()
|
closeDialog()
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,6 @@ 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
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.Settings.MenuTag
|
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.ShortSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
|
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.view.*
|
import org.yuzu.yuzu_emu.features.settings.model.view.*
|
||||||
import org.yuzu.yuzu_emu.utils.InputHandler
|
import org.yuzu.yuzu_emu.utils.InputHandler
|
||||||
import org.yuzu.yuzu_emu.utils.NativeConfig
|
import org.yuzu.yuzu_emu.utils.NativeConfig
|
||||||
@ -154,7 +153,6 @@ class SettingsFragmentPresenter(
|
|||||||
|
|
||||||
private fun addSystemSettings(sl: ArrayList<SettingsItem>) {
|
private fun addSystemSettings(sl: ArrayList<SettingsItem>) {
|
||||||
sl.apply {
|
sl.apply {
|
||||||
add(StringSetting.DEVICE_NAME.key)
|
|
||||||
add(BooleanSetting.RENDERER_USE_SPEED_LIMIT.key)
|
add(BooleanSetting.RENDERER_USE_SPEED_LIMIT.key)
|
||||||
add(ShortSetting.RENDERER_SPEED_LIMIT.key)
|
add(ShortSetting.RENDERER_SPEED_LIMIT.key)
|
||||||
add(BooleanSetting.USE_DOCKED_MODE.key)
|
add(BooleanSetting.USE_DOCKED_MODE.key)
|
||||||
@ -780,7 +778,7 @@ class SettingsFragmentPresenter(
|
|||||||
playerIndex: Int,
|
playerIndex: Int,
|
||||||
paramName: String,
|
paramName: String,
|
||||||
stick: NativeAnalog,
|
stick: NativeAnalog,
|
||||||
defaultValue: Float
|
defaultValue: Int
|
||||||
): AbstractIntSetting =
|
): AbstractIntSetting =
|
||||||
object : AbstractIntSetting {
|
object : AbstractIntSetting {
|
||||||
val params get() = NativeInput.getStickParam(playerIndex, stick)
|
val params get() = NativeInput.getStickParam(playerIndex, stick)
|
||||||
@ -788,7 +786,7 @@ class SettingsFragmentPresenter(
|
|||||||
override val key = ""
|
override val key = ""
|
||||||
|
|
||||||
override fun getInt(needsGlobal: Boolean): Int =
|
override fun getInt(needsGlobal: Boolean): Int =
|
||||||
(params.get(paramName, defaultValue) * 100).toInt()
|
(params.get(paramName, 0.15f) * 100).toInt()
|
||||||
|
|
||||||
override fun setInt(value: Int) {
|
override fun setInt(value: Int) {
|
||||||
val tempParams = params
|
val tempParams = params
|
||||||
@ -796,12 +794,12 @@ class SettingsFragmentPresenter(
|
|||||||
NativeInput.setStickParam(playerIndex, stick, tempParams)
|
NativeInput.setStickParam(playerIndex, stick, tempParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val defaultValue = (defaultValue * 100).toInt()
|
override val defaultValue = defaultValue
|
||||||
|
|
||||||
override fun getValueAsString(needsGlobal: Boolean): String =
|
override fun getValueAsString(needsGlobal: Boolean): String =
|
||||||
getInt(needsGlobal).toString()
|
getInt(needsGlobal).toString()
|
||||||
|
|
||||||
override fun reset() = setInt(this.defaultValue)
|
override fun reset() = setInt(defaultValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getExtraStickSettings(
|
private fun getExtraStickSettings(
|
||||||
@ -811,11 +809,11 @@ class SettingsFragmentPresenter(
|
|||||||
val stickIsController =
|
val stickIsController =
|
||||||
NativeInput.isController(NativeInput.getStickParam(playerIndex, nativeAnalog))
|
NativeInput.isController(NativeInput.getStickParam(playerIndex, nativeAnalog))
|
||||||
val modifierRangeSetting =
|
val modifierRangeSetting =
|
||||||
getStickIntSettingFromParam(playerIndex, "modifier_scale", nativeAnalog, 0.5f)
|
getStickIntSettingFromParam(playerIndex, "modifier_scale", nativeAnalog, 50)
|
||||||
val stickRangeSetting =
|
val stickRangeSetting =
|
||||||
getStickIntSettingFromParam(playerIndex, "range", nativeAnalog, 0.95f)
|
getStickIntSettingFromParam(playerIndex, "range", nativeAnalog, 95)
|
||||||
val stickDeadzoneSetting =
|
val stickDeadzoneSetting =
|
||||||
getStickIntSettingFromParam(playerIndex, "deadzone", nativeAnalog, 0.15f)
|
getStickIntSettingFromParam(playerIndex, "deadzone", nativeAnalog, 15)
|
||||||
|
|
||||||
val out = mutableListOf<SettingsItem>().apply {
|
val out = mutableListOf<SettingsItem>().apply {
|
||||||
if (stickIsController) {
|
if (stickIsController) {
|
||||||
|
@ -13,6 +13,7 @@ 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.DateTimeSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
|
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
|
||||||
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
|
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
|
||||||
|
import org.yuzu.yuzu_emu.utils.NativeConfig
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
||||||
|
|
||||||
class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
|
class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
|
||||||
@ -31,7 +32,9 @@ class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA
|
|||||||
val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
|
val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
|
||||||
binding.textSettingValue.text = dateFormatter.format(zonedTime)
|
binding.textSettingValue.text = dateFormatter.format(zonedTime)
|
||||||
|
|
||||||
binding.buttonClear.setVisible(setting.clearable)
|
binding.buttonClear.setVisible(
|
||||||
|
!setting.setting.global || NativeConfig.isPerGameConfigLoaded()
|
||||||
|
)
|
||||||
binding.buttonClear.setOnClickListener {
|
binding.buttonClear.setOnClickListener {
|
||||||
adapter.onClearClick(setting, bindingAdapterPosition)
|
adapter.onClearClick(setting, bindingAdapterPosition)
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ 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.SingleChoiceSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting
|
import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
|
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
|
||||||
|
import org.yuzu.yuzu_emu.utils.NativeConfig
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
||||||
|
|
||||||
class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
|
class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
|
||||||
@ -47,7 +48,9 @@ class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Setti
|
|||||||
binding.textSettingValue.setVisible(false)
|
binding.textSettingValue.setVisible(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.buttonClear.setVisible(setting.clearable)
|
binding.buttonClear.setVisible(
|
||||||
|
!setting.setting.global || NativeConfig.isPerGameConfigLoaded()
|
||||||
|
)
|
||||||
binding.buttonClear.setOnClickListener {
|
binding.buttonClear.setOnClickListener {
|
||||||
adapter.onClearClick(setting, bindingAdapterPosition)
|
adapter.onClearClick(setting, bindingAdapterPosition)
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ 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.SettingsItem
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting
|
import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
|
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
|
||||||
|
import org.yuzu.yuzu_emu.utils.NativeConfig
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
||||||
|
|
||||||
class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
|
class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
|
||||||
@ -27,7 +28,9 @@ class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAda
|
|||||||
setting.units
|
setting.units
|
||||||
)
|
)
|
||||||
|
|
||||||
binding.buttonClear.setVisible(setting.clearable)
|
binding.buttonClear.setVisible(
|
||||||
|
!setting.setting.global || NativeConfig.isPerGameConfigLoaded()
|
||||||
|
)
|
||||||
binding.buttonClear.setOnClickListener {
|
binding.buttonClear.setOnClickListener {
|
||||||
adapter.onClearClick(setting, bindingAdapterPosition)
|
adapter.onClearClick(setting, bindingAdapterPosition)
|
||||||
}
|
}
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
// 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,6 +9,7 @@ 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.SettingsItem
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.view.SwitchSetting
|
import org.yuzu.yuzu_emu.features.settings.model.view.SwitchSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
|
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
|
||||||
|
import org.yuzu.yuzu_emu.utils.NativeConfig
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
||||||
|
|
||||||
class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter: SettingsAdapter) :
|
class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter: SettingsAdapter) :
|
||||||
@ -28,7 +29,9 @@ class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter
|
|||||||
adapter.onBooleanClick(setting, binding.switchWidget.isChecked, bindingAdapterPosition)
|
adapter.onBooleanClick(setting, binding.switchWidget.isChecked, bindingAdapterPosition)
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.buttonClear.setVisible(setting.clearable)
|
binding.buttonClear.setVisible(
|
||||||
|
!setting.setting.global || NativeConfig.isPerGameConfigLoaded()
|
||||||
|
)
|
||||||
binding.buttonClear.setOnClickListener {
|
binding.buttonClear.setOnClickListener {
|
||||||
adapter.onClearClick(setting, bindingAdapterPosition)
|
adapter.onClearClick(setting, bindingAdapterPosition)
|
||||||
}
|
}
|
||||||
|
@ -810,7 +810,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
binding.doneControlConfig.setVisible(true)
|
binding.doneControlConfig.setVisible(false)
|
||||||
binding.surfaceInputOverlay.setIsInEditMode(true)
|
binding.surfaceInputOverlay.setIsInEditMode(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,6 @@ import org.yuzu.yuzu_emu.features.input.NativeInput
|
|||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
import org.yuzu.yuzu_emu.features.input.model.NativeAnalog
|
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.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.BooleanSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
|
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
|
||||||
import org.yuzu.yuzu_emu.overlay.model.OverlayControl
|
import org.yuzu.yuzu_emu.overlay.model.OverlayControl
|
||||||
@ -100,9 +99,11 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
var shouldUpdateView = false
|
var shouldUpdateView = false
|
||||||
val playerIndex = when (NativeInput.getStyleIndex(0)) {
|
val playerIndex =
|
||||||
NpadStyleIndex.Handheld -> 8
|
if (NativeInput.isHandheldOnly()) {
|
||||||
else -> 0
|
NativeInput.ConsoleDevice
|
||||||
|
} else {
|
||||||
|
NativeInput.Player1Device
|
||||||
}
|
}
|
||||||
|
|
||||||
for (button in overlayButtons) {
|
for (button in overlayButtons) {
|
||||||
@ -663,7 +664,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
|||||||
|
|
||||||
val overlayControlData = NativeConfig.getOverlayControlData()
|
val overlayControlData = NativeConfig.getOverlayControlData()
|
||||||
overlayControlData.forEach {
|
overlayControlData.forEach {
|
||||||
it.enabled = OverlayControl.from(it.id)?.defaultVisibility == true
|
it.enabled = OverlayControl.from(it.id)?.defaultVisibility == false
|
||||||
}
|
}
|
||||||
NativeConfig.setOverlayControlData(overlayControlData)
|
NativeConfig.setOverlayControlData(overlayControlData)
|
||||||
|
|
||||||
|
@ -292,9 +292,6 @@ void EmulationSession::ShutdownEmulation() {
|
|||||||
// Unload user input.
|
// Unload user input.
|
||||||
m_system.HIDCore().UnloadInputDevices();
|
m_system.HIDCore().UnloadInputDevices();
|
||||||
|
|
||||||
// Enable all controllers
|
|
||||||
m_system.HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All});
|
|
||||||
|
|
||||||
// Shutdown the main emulated process
|
// Shutdown the main emulated process
|
||||||
if (m_load_result == Core::SystemResultStatus::Success) {
|
if (m_load_result == Core::SystemResultStatus::Success) {
|
||||||
m_system.DetachDebugger();
|
m_system.DetachDebugger();
|
||||||
@ -407,9 +404,7 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath,
|
|||||||
const size_t program_index,
|
const size_t program_index,
|
||||||
const bool frontend_initiated) {
|
const bool frontend_initiated) {
|
||||||
MicroProfileOnThreadCreate("EmuThread");
|
MicroProfileOnThreadCreate("EmuThread");
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({ MicroProfileShutdown(); });
|
||||||
MicroProfileShutdown();
|
|
||||||
};
|
|
||||||
|
|
||||||
LOG_INFO(Frontend, "starting");
|
LOG_INFO(Frontend, "starting");
|
||||||
|
|
||||||
@ -418,9 +413,7 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath,
|
|||||||
return Core::SystemResultStatus::ErrorLoader;
|
return Core::SystemResultStatus::ErrorLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({ EmulationSession::GetInstance().ShutdownEmulation(); });
|
||||||
EmulationSession::GetInstance().ShutdownEmulation();
|
|
||||||
};
|
|
||||||
|
|
||||||
jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath, program_index,
|
jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath, program_index,
|
||||||
frontend_initiated);
|
frontend_initiated);
|
||||||
@ -668,7 +661,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmptyUserDirectory(JNIEnv*
|
|||||||
ASSERT(user_id);
|
ASSERT(user_id);
|
||||||
|
|
||||||
const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
|
const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
|
||||||
{}, vfs_nand_dir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Account, 1,
|
{}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData, 1,
|
||||||
user_id->AsU128(), 0);
|
user_id->AsU128(), 0);
|
||||||
|
|
||||||
const auto full_path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path);
|
const auto full_path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path);
|
||||||
@ -836,8 +829,8 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject j
|
|||||||
FileSys::OpenMode::Read);
|
FileSys::OpenMode::Read);
|
||||||
|
|
||||||
const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
|
const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
|
||||||
{}, vfsNandDir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Account, program_id,
|
{}, vfsNandDir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData,
|
||||||
user_id->AsU128(), 0);
|
program_id, user_id->AsU128(), 0);
|
||||||
return Common::Android::ToJString(env, user_save_data_path);
|
return Common::Android::ToJString(env, user_save_data_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,50 +102,8 @@ 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) {
|
void ConnectController(size_t player_index, bool connected) {
|
||||||
auto& hid_core = EmulationSession::GetInstance().System().HIDCore();
|
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) {
|
if (player_index == 0) {
|
||||||
auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld);
|
auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld);
|
||||||
auto* player_one = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1);
|
auto* player_one = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1);
|
||||||
@ -564,10 +522,36 @@ jint Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getButtonNameImpl(JNIEnv
|
|||||||
|
|
||||||
jintArray Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getSupportedStyleTagsImpl(
|
jintArray Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getSupportedStyleTagsImpl(
|
||||||
JNIEnv* env, jobject j_obj, jint j_player_index) {
|
JNIEnv* env, jobject j_obj, jint j_player_index) {
|
||||||
auto supported_styles = GetSupportedStyles(j_player_index);
|
auto& hid_core = EmulationSession::GetInstance().System().HIDCore();
|
||||||
jintArray j_supported_indexes = env->NewIntArray(supported_styles.size());
|
const auto npad_style_set = hid_core.GetSupportedStyleTag();
|
||||||
env->SetIntArrayRegion(j_supported_indexes, 0, supported_styles.size(),
|
std::vector<s32> supported_indexes;
|
||||||
supported_styles.data());
|
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());
|
||||||
return j_supported_indexes;
|
return j_supported_indexes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,7 +209,6 @@
|
|||||||
<string name="value_with_units">%1$s%2$s</string>
|
<string name="value_with_units">%1$s%2$s</string>
|
||||||
|
|
||||||
<!-- System settings strings -->
|
<!-- System settings strings -->
|
||||||
<string name="device_name">Device name</string>
|
|
||||||
<string name="use_docked_mode">Docked Mode</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="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>
|
<string name="emulated_region">Emulated region</string>
|
||||||
|
@ -73,15 +73,16 @@ void Manager::BufferReleaseAndRegister() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 Manager::GetDeviceNames(std::span<Renderer::AudioDevice::AudioDeviceName> names,
|
u32 Manager::GetDeviceNames(std::vector<Renderer::AudioDevice::AudioDeviceName>& names,
|
||||||
|
[[maybe_unused]] const u32 max_count,
|
||||||
[[maybe_unused]] const bool filter) {
|
[[maybe_unused]] const bool filter) {
|
||||||
std::scoped_lock l{mutex};
|
std::scoped_lock l{mutex};
|
||||||
|
|
||||||
LinkToManager();
|
LinkToManager();
|
||||||
|
|
||||||
auto input_devices{Sink::GetDeviceListForSink(Settings::values.sink_id.GetValue(), true)};
|
auto input_devices{Sink::GetDeviceListForSink(Settings::values.sink_id.GetValue(), true)};
|
||||||
if (!input_devices.empty() && !names.empty()) {
|
if (input_devices.size() > 1) {
|
||||||
names[0] = Renderer::AudioDevice::AudioDeviceName("Uac");
|
names.emplace_back("Uac");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -60,11 +60,13 @@ public:
|
|||||||
* Get a list of audio in device names.
|
* Get a list of audio in device names.
|
||||||
*
|
*
|
||||||
* @param names - Output container to write names to.
|
* @param names - Output container to write names to.
|
||||||
|
* @param max_count - Maximum number of device names to write. Unused
|
||||||
* @param filter - Should the list be filtered? Unused.
|
* @param filter - Should the list be filtered? Unused.
|
||||||
*
|
*
|
||||||
* @return Number of names written.
|
* @return Number of names written.
|
||||||
*/
|
*/
|
||||||
u32 GetDeviceNames(std::span<Renderer::AudioDevice::AudioDeviceName> names, bool filter);
|
u32 GetDeviceNames(std::vector<Renderer::AudioDevice::AudioDeviceName>& names, u32 max_count,
|
||||||
|
bool filter);
|
||||||
|
|
||||||
/// Core system
|
/// Core system
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
|
@ -146,11 +146,11 @@ public:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tags[released++] = tag;
|
||||||
|
|
||||||
if (released >= tags.size()) {
|
if (released >= tags.size()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
tags[released++] = tag;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return released;
|
return released;
|
||||||
|
@ -28,8 +28,8 @@ OpusDecoder::~OpusDecoder() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result OpusDecoder::Initialize(const OpusParametersEx& params,
|
Result OpusDecoder::Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory,
|
||||||
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) {
|
u64 transfer_memory_size) {
|
||||||
auto frame_size{params.use_large_frame_size ? 5760 : 1920};
|
auto frame_size{params.use_large_frame_size ? 5760 : 1920};
|
||||||
shared_buffer_size = transfer_memory_size;
|
shared_buffer_size = transfer_memory_size;
|
||||||
shared_buffer = std::make_unique<u8[]>(shared_buffer_size);
|
shared_buffer = std::make_unique<u8[]>(shared_buffer_size);
|
||||||
@ -59,7 +59,7 @@ Result OpusDecoder::Initialize(const OpusParametersEx& params,
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result OpusDecoder::Initialize(const OpusMultiStreamParametersEx& params,
|
Result OpusDecoder::Initialize(OpusMultiStreamParametersEx& params,
|
||||||
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) {
|
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) {
|
||||||
auto frame_size{params.use_large_frame_size ? 5760 : 1920};
|
auto frame_size{params.use_large_frame_size ? 5760 : 1920};
|
||||||
shared_buffer_size = transfer_memory_size;
|
shared_buffer_size = transfer_memory_size;
|
||||||
|
@ -22,10 +22,10 @@ public:
|
|||||||
explicit OpusDecoder(Core::System& system, HardwareOpus& hardware_opus_);
|
explicit OpusDecoder(Core::System& system, HardwareOpus& hardware_opus_);
|
||||||
~OpusDecoder();
|
~OpusDecoder();
|
||||||
|
|
||||||
Result Initialize(const OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory,
|
Result Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory,
|
||||||
|
u64 transfer_memory_size);
|
||||||
|
Result Initialize(OpusMultiStreamParametersEx& params, Kernel::KTransferMemory* transfer_memory,
|
||||||
u64 transfer_memory_size);
|
u64 transfer_memory_size);
|
||||||
Result Initialize(const OpusMultiStreamParametersEx& params,
|
|
||||||
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size);
|
|
||||||
Result DecodeInterleaved(u32* out_data_size, u64* out_time_taken, u32* out_sample_count,
|
Result DecodeInterleaved(u32* out_data_size, u64* out_time_taken, u32* out_sample_count,
|
||||||
std::span<const u8> input_data, std::span<u8> output_data, bool reset);
|
std::span<const u8> input_data, std::span<u8> output_data, bool reset);
|
||||||
Result SetContext([[maybe_unused]] std::span<const u8> context);
|
Result SetContext([[maybe_unused]] std::span<const u8> context);
|
||||||
|
@ -38,7 +38,7 @@ OpusDecoderManager::OpusDecoderManager(Core::System& system_)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result OpusDecoderManager::GetWorkBufferSize(const OpusParameters& params, u32& out_size) {
|
Result OpusDecoderManager::GetWorkBufferSize(OpusParameters& params, u64& out_size) {
|
||||||
OpusParametersEx ex{
|
OpusParametersEx ex{
|
||||||
.sample_rate = params.sample_rate,
|
.sample_rate = params.sample_rate,
|
||||||
.channel_count = params.channel_count,
|
.channel_count = params.channel_count,
|
||||||
@ -47,11 +47,11 @@ Result OpusDecoderManager::GetWorkBufferSize(const OpusParameters& params, u32&
|
|||||||
R_RETURN(GetWorkBufferSizeExEx(ex, out_size));
|
R_RETURN(GetWorkBufferSizeExEx(ex, out_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result OpusDecoderManager::GetWorkBufferSizeEx(const OpusParametersEx& params, u32& out_size) {
|
Result OpusDecoderManager::GetWorkBufferSizeEx(OpusParametersEx& params, u64& out_size) {
|
||||||
R_RETURN(GetWorkBufferSizeExEx(params, out_size));
|
R_RETURN(GetWorkBufferSizeExEx(params, out_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result OpusDecoderManager::GetWorkBufferSizeExEx(const OpusParametersEx& params, u32& out_size) {
|
Result OpusDecoderManager::GetWorkBufferSizeExEx(OpusParametersEx& params, u64& out_size) {
|
||||||
R_UNLESS(IsValidChannelCount(params.channel_count), ResultInvalidOpusChannelCount);
|
R_UNLESS(IsValidChannelCount(params.channel_count), ResultInvalidOpusChannelCount);
|
||||||
R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate);
|
R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate);
|
||||||
|
|
||||||
@ -63,8 +63,8 @@ Result OpusDecoderManager::GetWorkBufferSizeExEx(const OpusParametersEx& params,
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(const OpusMultiStreamParameters& params,
|
Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(OpusMultiStreamParameters& params,
|
||||||
u32& out_size) {
|
u64& out_size) {
|
||||||
OpusMultiStreamParametersEx ex{
|
OpusMultiStreamParametersEx ex{
|
||||||
.sample_rate = params.sample_rate,
|
.sample_rate = params.sample_rate,
|
||||||
.channel_count = params.channel_count,
|
.channel_count = params.channel_count,
|
||||||
@ -76,13 +76,13 @@ Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(const OpusMultiStream
|
|||||||
R_RETURN(GetWorkBufferSizeForMultiStreamExEx(ex, out_size));
|
R_RETURN(GetWorkBufferSizeForMultiStreamExEx(ex, out_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamEx(
|
Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamEx(OpusMultiStreamParametersEx& params,
|
||||||
const OpusMultiStreamParametersEx& params, u32& out_size) {
|
u64& out_size) {
|
||||||
R_RETURN(GetWorkBufferSizeForMultiStreamExEx(params, out_size));
|
R_RETURN(GetWorkBufferSizeForMultiStreamExEx(params, out_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx(
|
Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx(OpusMultiStreamParametersEx& params,
|
||||||
const OpusMultiStreamParametersEx& params, u32& out_size) {
|
u64& out_size) {
|
||||||
R_UNLESS(IsValidMultiStreamChannelCount(params.channel_count), ResultInvalidOpusChannelCount);
|
R_UNLESS(IsValidMultiStreamChannelCount(params.channel_count), ResultInvalidOpusChannelCount);
|
||||||
R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate);
|
R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate);
|
||||||
R_UNLESS(IsValidStreamCount(params.channel_count, params.total_stream_count,
|
R_UNLESS(IsValidStreamCount(params.channel_count, params.total_stream_count,
|
||||||
|
@ -22,19 +22,17 @@ public:
|
|||||||
return hardware_opus;
|
return hardware_opus;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GetWorkBufferSize(const OpusParameters& params, u32& out_size);
|
Result GetWorkBufferSize(OpusParameters& params, u64& out_size);
|
||||||
Result GetWorkBufferSizeEx(const OpusParametersEx& params, u32& out_size);
|
Result GetWorkBufferSizeEx(OpusParametersEx& params, u64& out_size);
|
||||||
Result GetWorkBufferSizeExEx(const OpusParametersEx& params, u32& out_size);
|
Result GetWorkBufferSizeExEx(OpusParametersEx& params, u64& out_size);
|
||||||
Result GetWorkBufferSizeForMultiStream(const OpusMultiStreamParameters& params, u32& out_size);
|
Result GetWorkBufferSizeForMultiStream(OpusMultiStreamParameters& params, u64& out_size);
|
||||||
Result GetWorkBufferSizeForMultiStreamEx(const OpusMultiStreamParametersEx& params,
|
Result GetWorkBufferSizeForMultiStreamEx(OpusMultiStreamParametersEx& params, u64& out_size);
|
||||||
u32& out_size);
|
Result GetWorkBufferSizeForMultiStreamExEx(OpusMultiStreamParametersEx& params, u64& out_size);
|
||||||
Result GetWorkBufferSizeForMultiStreamExEx(const OpusMultiStreamParametersEx& params,
|
|
||||||
u32& out_size);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
HardwareOpus hardware_opus;
|
HardwareOpus hardware_opus;
|
||||||
std::array<u32, MaxChannels> required_workbuffer_sizes{};
|
std::array<u64, MaxChannels> required_workbuffer_sizes{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace AudioCore::OpusDecoder
|
} // namespace AudioCore::OpusDecoder
|
||||||
|
@ -42,7 +42,7 @@ HardwareOpus::HardwareOpus(Core::System& system_)
|
|||||||
opus_decoder.SetSharedMemory(shared_memory);
|
opus_decoder.SetSharedMemory(shared_memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 HardwareOpus::GetWorkBufferSize(u32 channel) {
|
u64 HardwareOpus::GetWorkBufferSize(u32 channel) {
|
||||||
if (!opus_decoder.IsRunning()) {
|
if (!opus_decoder.IsRunning()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -55,10 +55,10 @@ u32 HardwareOpus::GetWorkBufferSize(u32 channel) {
|
|||||||
ADSP::OpusDecoder::Message::GetWorkBufferSizeOK, msg);
|
ADSP::OpusDecoder::Message::GetWorkBufferSizeOK, msg);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return static_cast<u32>(shared_memory.dsp_return_data[0]);
|
return shared_memory.dsp_return_data[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count) {
|
u64 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count) {
|
||||||
std::scoped_lock l{mutex};
|
std::scoped_lock l{mutex};
|
||||||
shared_memory.host_send_data[0] = total_stream_count;
|
shared_memory.host_send_data[0] = total_stream_count;
|
||||||
shared_memory.host_send_data[1] = stereo_stream_count;
|
shared_memory.host_send_data[1] = stereo_stream_count;
|
||||||
@ -70,7 +70,7 @@ u32 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 st
|
|||||||
ADSP::OpusDecoder::Message::GetWorkBufferSizeForMultiStreamOK, msg);
|
ADSP::OpusDecoder::Message::GetWorkBufferSizeForMultiStreamOK, msg);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return static_cast<u32>(shared_memory.dsp_return_data[0]);
|
return shared_memory.dsp_return_data[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
Result HardwareOpus::InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer,
|
Result HardwareOpus::InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer,
|
||||||
@ -94,9 +94,8 @@ Result HardwareOpus::InitializeDecodeObject(u32 sample_rate, u32 channel_count,
|
|||||||
|
|
||||||
Result HardwareOpus::InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count,
|
Result HardwareOpus::InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count,
|
||||||
u32 total_stream_count,
|
u32 total_stream_count,
|
||||||
u32 stereo_stream_count,
|
u32 stereo_stream_count, void* mappings,
|
||||||
const void* mappings, void* buffer,
|
void* buffer, u64 buffer_size) {
|
||||||
u64 buffer_size) {
|
|
||||||
std::scoped_lock l{mutex};
|
std::scoped_lock l{mutex};
|
||||||
shared_memory.host_send_data[0] = (u64)buffer;
|
shared_memory.host_send_data[0] = (u64)buffer;
|
||||||
shared_memory.host_send_data[1] = buffer_size;
|
shared_memory.host_send_data[1] = buffer_size;
|
||||||
|
@ -16,14 +16,14 @@ class HardwareOpus {
|
|||||||
public:
|
public:
|
||||||
HardwareOpus(Core::System& system);
|
HardwareOpus(Core::System& system);
|
||||||
|
|
||||||
u32 GetWorkBufferSize(u32 channel);
|
u64 GetWorkBufferSize(u32 channel);
|
||||||
u32 GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count);
|
u64 GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count);
|
||||||
|
|
||||||
Result InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer,
|
Result InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer,
|
||||||
u64 buffer_size);
|
u64 buffer_size);
|
||||||
Result InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count,
|
Result InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count,
|
||||||
u32 totaL_stream_count, u32 stereo_stream_count,
|
u32 totaL_stream_count, u32 stereo_stream_count,
|
||||||
const void* mappings, void* buffer, u64 buffer_size);
|
void* mappings, void* buffer, u64 buffer_size);
|
||||||
Result ShutdownDecodeObject(void* buffer, u64 buffer_size);
|
Result ShutdownDecodeObject(void* buffer, u64 buffer_size);
|
||||||
Result ShutdownMultiStreamDecodeObject(void* buffer, u64 buffer_size);
|
Result ShutdownMultiStreamDecodeObject(void* buffer, u64 buffer_size);
|
||||||
Result DecodeInterleaved(u32& out_sample_count, void* output_data, u64 output_data_size,
|
Result DecodeInterleaved(u32& out_sample_count, void* output_data, u64 output_data_size,
|
||||||
|
@ -20,7 +20,7 @@ struct OpusParametersEx {
|
|||||||
/* 0x00 */ u32 sample_rate;
|
/* 0x00 */ u32 sample_rate;
|
||||||
/* 0x04 */ u32 channel_count;
|
/* 0x04 */ u32 channel_count;
|
||||||
/* 0x08 */ bool use_large_frame_size;
|
/* 0x08 */ bool use_large_frame_size;
|
||||||
/* 0x09 */ INSERT_PADDING_BYTES_NOINIT(7);
|
/* 0x09 */ INSERT_PADDING_BYTES(7);
|
||||||
}; // size = 0x10
|
}; // size = 0x10
|
||||||
static_assert(sizeof(OpusParametersEx) == 0x10, "OpusParametersEx has the wrong size!");
|
static_assert(sizeof(OpusParametersEx) == 0x10, "OpusParametersEx has the wrong size!");
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ struct OpusMultiStreamParametersEx {
|
|||||||
/* 0x08 */ u32 total_stream_count;
|
/* 0x08 */ u32 total_stream_count;
|
||||||
/* 0x0C */ u32 stereo_stream_count;
|
/* 0x0C */ u32 stereo_stream_count;
|
||||||
/* 0x10 */ bool use_large_frame_size;
|
/* 0x10 */ bool use_large_frame_size;
|
||||||
/* 0x11 */ INSERT_PADDING_BYTES_NOINIT(7);
|
/* 0x11 */ INSERT_PADDING_BYTES(7);
|
||||||
/* 0x18 */ std::array<u8, OpusStreamCountMax + 1> mappings;
|
/* 0x18 */ std::array<u8, OpusStreamCountMax + 1> mappings;
|
||||||
}; // size = 0x118
|
}; // size = 0x118
|
||||||
static_assert(sizeof(OpusMultiStreamParametersEx) == 0x118,
|
static_assert(sizeof(OpusMultiStreamParametersEx) == 0x118,
|
||||||
|
@ -36,7 +36,8 @@ AudioDevice::AudioDevice(Core::System& system, const u64 applet_resource_user_id
|
|||||||
: output_sink{system.AudioCore().GetOutputSink()},
|
: output_sink{system.AudioCore().GetOutputSink()},
|
||||||
applet_resource_user_id{applet_resource_user_id_}, user_revision{revision} {}
|
applet_resource_user_id{applet_resource_user_id_}, user_revision{revision} {}
|
||||||
|
|
||||||
u32 AudioDevice::ListAudioDeviceName(std::span<AudioDeviceName> out_buffer) const {
|
u32 AudioDevice::ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer,
|
||||||
|
const size_t max_count) const {
|
||||||
std::span<const AudioDeviceName> names{};
|
std::span<const AudioDeviceName> names{};
|
||||||
|
|
||||||
if (CheckFeatureSupported(SupportTags::AudioUsbDeviceOutput, user_revision)) {
|
if (CheckFeatureSupported(SupportTags::AudioUsbDeviceOutput, user_revision)) {
|
||||||
@ -45,18 +46,19 @@ u32 AudioDevice::ListAudioDeviceName(std::span<AudioDeviceName> out_buffer) cons
|
|||||||
names = device_names;
|
names = device_names;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 out_count{static_cast<u32>(std::min(out_buffer.size(), names.size()))};
|
const u32 out_count{static_cast<u32>(std::min(max_count, names.size()))};
|
||||||
for (u32 i = 0; i < out_count; i++) {
|
for (u32 i = 0; i < out_count; i++) {
|
||||||
out_buffer[i] = names[i];
|
out_buffer.push_back(names[i]);
|
||||||
}
|
}
|
||||||
return out_count;
|
return out_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 AudioDevice::ListAudioOutputDeviceName(std::span<AudioDeviceName> out_buffer) const {
|
u32 AudioDevice::ListAudioOutputDeviceName(std::vector<AudioDeviceName>& out_buffer,
|
||||||
const u32 out_count{static_cast<u32>(std::min(out_buffer.size(), output_device_names.size()))};
|
const size_t max_count) const {
|
||||||
|
const u32 out_count{static_cast<u32>(std::min(max_count, output_device_names.size()))};
|
||||||
|
|
||||||
for (u32 i = 0; i < out_count; i++) {
|
for (u32 i = 0; i < out_count; i++) {
|
||||||
out_buffer[i] = output_device_names[i];
|
out_buffer.push_back(output_device_names[i]);
|
||||||
}
|
}
|
||||||
return out_count;
|
return out_count;
|
||||||
}
|
}
|
||||||
|
@ -36,18 +36,20 @@ public:
|
|||||||
* Get a list of the available output devices.
|
* Get a list of the available output devices.
|
||||||
*
|
*
|
||||||
* @param out_buffer - Output buffer to write the available device names.
|
* @param out_buffer - Output buffer to write the available device names.
|
||||||
|
* @param max_count - Maximum number of devices to write (count of out_buffer).
|
||||||
* @return Number of device names written.
|
* @return Number of device names written.
|
||||||
*/
|
*/
|
||||||
u32 ListAudioDeviceName(std::span<AudioDeviceName> out_buffer) const;
|
u32 ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer, size_t max_count) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a list of the available output devices.
|
* Get a list of the available output devices.
|
||||||
* Different to above somehow...
|
* Different to above somehow...
|
||||||
*
|
*
|
||||||
* @param out_buffer - Output buffer to write the available device names.
|
* @param out_buffer - Output buffer to write the available device names.
|
||||||
|
* @param max_count - Maximum number of devices to write (count of out_buffer).
|
||||||
* @return Number of device names written.
|
* @return Number of device names written.
|
||||||
*/
|
*/
|
||||||
u32 ListAudioOutputDeviceName(std::span<AudioDeviceName> out_buffer) const;
|
u32 ListAudioOutputDeviceName(std::vector<AudioDeviceName>& out_buffer, size_t max_count) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the volume of all streams in the backend sink.
|
* Set the volume of all streams in the backend sink.
|
||||||
|
@ -17,8 +17,9 @@ Renderer::Renderer(Core::System& system_, Manager& manager_, Kernel::KEvent* ren
|
|||||||
|
|
||||||
Result Renderer::Initialize(const AudioRendererParameterInternal& params,
|
Result Renderer::Initialize(const AudioRendererParameterInternal& params,
|
||||||
Kernel::KTransferMemory* transfer_memory,
|
Kernel::KTransferMemory* transfer_memory,
|
||||||
const u64 transfer_memory_size, Kernel::KProcess* process_handle,
|
const u64 transfer_memory_size, const u32 process_handle,
|
||||||
const u64 applet_resource_user_id, const s32 session_id) {
|
Kernel::KProcess& process, const u64 applet_resource_user_id,
|
||||||
|
const s32 session_id) {
|
||||||
if (params.execution_mode == ExecutionMode::Auto) {
|
if (params.execution_mode == ExecutionMode::Auto) {
|
||||||
if (!manager.AddSystem(system)) {
|
if (!manager.AddSystem(system)) {
|
||||||
LOG_ERROR(Service_Audio,
|
LOG_ERROR(Service_Audio,
|
||||||
@ -29,7 +30,7 @@ Result Renderer::Initialize(const AudioRendererParameterInternal& params,
|
|||||||
}
|
}
|
||||||
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
system.Initialize(params, transfer_memory, transfer_memory_size, process_handle,
|
system.Initialize(params, transfer_memory, transfer_memory_size, process_handle, process,
|
||||||
applet_resource_user_id, session_id);
|
applet_resource_user_id, session_id);
|
||||||
|
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
|
@ -38,14 +38,14 @@ public:
|
|||||||
* @param params - Input parameters to initialize the system with.
|
* @param params - Input parameters to initialize the system with.
|
||||||
* @param transfer_memory - Game-supplied memory for all workbuffers. Unused.
|
* @param transfer_memory - Game-supplied memory for all workbuffers. Unused.
|
||||||
* @param transfer_memory_size - Size of the transfer memory. Unused.
|
* @param transfer_memory_size - Size of the transfer memory. Unused.
|
||||||
* @param process_handle - Process handle, also used for memory.
|
* @param process_handle - Process handle, also used for memory. Unused.
|
||||||
* @param applet_resource_user_id - Applet id for this renderer. Unused.
|
* @param applet_resource_user_id - Applet id for this renderer. Unused.
|
||||||
* @param session_id - Session id of this renderer.
|
* @param session_id - Session id of this renderer.
|
||||||
* @return Result code.
|
* @return Result code.
|
||||||
*/
|
*/
|
||||||
Result Initialize(const AudioRendererParameterInternal& params,
|
Result Initialize(const AudioRendererParameterInternal& params,
|
||||||
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
|
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
|
||||||
Kernel::KProcess* process_handle, u64 applet_resource_user_id,
|
u32 process_handle, Kernel::KProcess& process, u64 applet_resource_user_id,
|
||||||
s32 session_id);
|
s32 session_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
namespace AudioCore::Renderer {
|
namespace AudioCore::Renderer {
|
||||||
|
|
||||||
InfoUpdater::InfoUpdater(std::span<const u8> input_, std::span<u8> output_,
|
InfoUpdater::InfoUpdater(std::span<const u8> input_, std::span<u8> output_,
|
||||||
Kernel::KProcess* process_handle_, BehaviorInfo& behaviour_)
|
const u32 process_handle_, BehaviorInfo& behaviour_)
|
||||||
: input{input_.data() + sizeof(UpdateDataHeader)},
|
: input{input_.data() + sizeof(UpdateDataHeader)},
|
||||||
input_origin{input_}, output{output_.data() + sizeof(UpdateDataHeader)},
|
input_origin{input_}, output{output_.data() + sizeof(UpdateDataHeader)},
|
||||||
output_origin{output_}, in_header{reinterpret_cast<const UpdateDataHeader*>(
|
output_origin{output_}, in_header{reinterpret_cast<const UpdateDataHeader*>(
|
||||||
|
@ -8,10 +8,6 @@
|
|||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/hle/service/audio/errors.h"
|
#include "core/hle/service/audio/errors.h"
|
||||||
|
|
||||||
namespace Kernel {
|
|
||||||
class KProcess;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace AudioCore::Renderer {
|
namespace AudioCore::Renderer {
|
||||||
class BehaviorInfo;
|
class BehaviorInfo;
|
||||||
class VoiceContext;
|
class VoiceContext;
|
||||||
@ -43,8 +39,8 @@ class InfoUpdater {
|
|||||||
static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has the wrong size!");
|
static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has the wrong size!");
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit InfoUpdater(std::span<const u8> input, std::span<u8> output,
|
explicit InfoUpdater(std::span<const u8> input, std::span<u8> output, u32 process_handle,
|
||||||
Kernel::KProcess* process_handle, BehaviorInfo& behaviour);
|
BehaviorInfo& behaviour);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the voice channel resources.
|
* Update the voice channel resources.
|
||||||
@ -201,7 +197,7 @@ private:
|
|||||||
/// Expected output size, see CheckConsumedSize
|
/// Expected output size, see CheckConsumedSize
|
||||||
u64 expected_output_size;
|
u64 expected_output_size;
|
||||||
/// Unused
|
/// Unused
|
||||||
Kernel::KProcess* process_handle;
|
u32 process_handle;
|
||||||
/// Behaviour
|
/// Behaviour
|
||||||
BehaviorInfo& behaviour;
|
BehaviorInfo& behaviour;
|
||||||
};
|
};
|
||||||
|
@ -8,11 +8,11 @@
|
|||||||
|
|
||||||
namespace AudioCore::Renderer {
|
namespace AudioCore::Renderer {
|
||||||
|
|
||||||
PoolMapper::PoolMapper(Kernel::KProcess* process_handle_, bool force_map_)
|
PoolMapper::PoolMapper(u32 process_handle_, bool force_map_)
|
||||||
: process_handle{process_handle_}, force_map{force_map_} {}
|
: process_handle{process_handle_}, force_map{force_map_} {}
|
||||||
|
|
||||||
PoolMapper::PoolMapper(Kernel::KProcess* process_handle_, std::span<MemoryPoolInfo> pool_infos_,
|
PoolMapper::PoolMapper(u32 process_handle_, std::span<MemoryPoolInfo> pool_infos_, u32 pool_count_,
|
||||||
u32 pool_count_, bool force_map_)
|
bool force_map_)
|
||||||
: process_handle{process_handle_}, pool_infos{pool_infos_.data()},
|
: process_handle{process_handle_}, pool_infos{pool_infos_.data()},
|
||||||
pool_count{pool_count_}, force_map{force_map_} {}
|
pool_count{pool_count_}, force_map{force_map_} {}
|
||||||
|
|
||||||
@ -106,17 +106,15 @@ bool PoolMapper::IsForceMapEnabled() const {
|
|||||||
return force_map;
|
return force_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
Kernel::KProcess* PoolMapper::GetProcessHandle(const MemoryPoolInfo* pool) const {
|
u32 PoolMapper::GetProcessHandle(const MemoryPoolInfo* pool) const {
|
||||||
switch (pool->GetLocation()) {
|
switch (pool->GetLocation()) {
|
||||||
case MemoryPoolInfo::Location::CPU:
|
case MemoryPoolInfo::Location::CPU:
|
||||||
return process_handle;
|
return process_handle;
|
||||||
case MemoryPoolInfo::Location::DSP:
|
case MemoryPoolInfo::Location::DSP:
|
||||||
// return Kernel::Svc::CurrentProcess;
|
return Kernel::Svc::CurrentProcess;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
LOG_WARNING(Service_Audio, "Invalid MemoryPoolInfo location!");
|
LOG_WARNING(Service_Audio, "Invalid MemoryPoolInfo location!");
|
||||||
// return Kernel::Svc::CurrentProcess;
|
return Kernel::Svc::CurrentProcess;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PoolMapper::Map([[maybe_unused]] const u32 handle, [[maybe_unused]] const CpuAddr cpu_addr,
|
bool PoolMapper::Map([[maybe_unused]] const u32 handle, [[maybe_unused]] const CpuAddr cpu_addr,
|
||||||
@ -149,14 +147,14 @@ bool PoolMapper::Unmap([[maybe_unused]] const u32 handle, [[maybe_unused]] const
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool PoolMapper::Unmap(MemoryPoolInfo& pool) const {
|
bool PoolMapper::Unmap(MemoryPoolInfo& pool) const {
|
||||||
[[maybe_unused]] Kernel::KProcess* handle{};
|
[[maybe_unused]] u32 handle{0};
|
||||||
|
|
||||||
switch (pool.GetLocation()) {
|
switch (pool.GetLocation()) {
|
||||||
case MemoryPoolInfo::Location::CPU:
|
case MemoryPoolInfo::Location::CPU:
|
||||||
handle = process_handle;
|
handle = process_handle;
|
||||||
break;
|
break;
|
||||||
case MemoryPoolInfo::Location::DSP:
|
case MemoryPoolInfo::Location::DSP:
|
||||||
// handle = Kernel::Svc::CurrentProcess;
|
handle = Kernel::Svc::CurrentProcess;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// nn::audio::dsp::UnmapUserPointer(handle, pool->cpu_address, pool->size);
|
// nn::audio::dsp::UnmapUserPointer(handle, pool->cpu_address, pool->size);
|
||||||
|
@ -10,10 +10,6 @@
|
|||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/hle/service/audio/errors.h"
|
#include "core/hle/service/audio/errors.h"
|
||||||
|
|
||||||
namespace Kernel {
|
|
||||||
class KProcess;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace AudioCore::Renderer {
|
namespace AudioCore::Renderer {
|
||||||
class AddressInfo;
|
class AddressInfo;
|
||||||
|
|
||||||
@ -22,9 +18,9 @@ class AddressInfo;
|
|||||||
*/
|
*/
|
||||||
class PoolMapper {
|
class PoolMapper {
|
||||||
public:
|
public:
|
||||||
explicit PoolMapper(Kernel::KProcess* process_handle, bool force_map);
|
explicit PoolMapper(u32 process_handle, bool force_map);
|
||||||
explicit PoolMapper(Kernel::KProcess* process_handle, std::span<MemoryPoolInfo> pool_infos,
|
explicit PoolMapper(u32 process_handle, std::span<MemoryPoolInfo> pool_infos, u32 pool_count,
|
||||||
u32 pool_count, bool force_map);
|
bool force_map);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear the usage state for all given pools.
|
* Clear the usage state for all given pools.
|
||||||
@ -102,7 +98,7 @@ public:
|
|||||||
* @return CurrentProcessHandle if location == DSP,
|
* @return CurrentProcessHandle if location == DSP,
|
||||||
* the PoolMapper's process_handle if location == CPU
|
* the PoolMapper's process_handle if location == CPU
|
||||||
*/
|
*/
|
||||||
Kernel::KProcess* GetProcessHandle(const MemoryPoolInfo* pool) const;
|
u32 GetProcessHandle(const MemoryPoolInfo* pool) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map the given region with the given handle. This is a no-op.
|
* Map the given region with the given handle. This is a no-op.
|
||||||
@ -171,7 +167,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
/// Process handle for this mapper, used when location == CPU
|
/// Process handle for this mapper, used when location == CPU
|
||||||
Kernel::KProcess* process_handle{};
|
u32 process_handle;
|
||||||
/// List of memory pools assigned to this mapper
|
/// List of memory pools assigned to this mapper
|
||||||
MemoryPoolInfo* pool_infos{};
|
MemoryPoolInfo* pool_infos{};
|
||||||
/// The number of pools
|
/// The number of pools
|
||||||
|
@ -102,8 +102,8 @@ System::System(Core::System& core_, Kernel::KEvent* adsp_rendered_event_)
|
|||||||
|
|
||||||
Result System::Initialize(const AudioRendererParameterInternal& params,
|
Result System::Initialize(const AudioRendererParameterInternal& params,
|
||||||
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
|
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
|
||||||
Kernel::KProcess* process_handle_, u64 applet_resource_user_id_,
|
u32 process_handle_, Kernel::KProcess& process_,
|
||||||
s32 session_id_) {
|
u64 applet_resource_user_id_, s32 session_id_) {
|
||||||
if (!CheckValidRevision(params.revision)) {
|
if (!CheckValidRevision(params.revision)) {
|
||||||
return Service::Audio::ResultInvalidRevision;
|
return Service::Audio::ResultInvalidRevision;
|
||||||
}
|
}
|
||||||
@ -119,6 +119,7 @@ Result System::Initialize(const AudioRendererParameterInternal& params,
|
|||||||
behavior.SetUserLibRevision(params.revision);
|
behavior.SetUserLibRevision(params.revision);
|
||||||
|
|
||||||
process_handle = process_handle_;
|
process_handle = process_handle_;
|
||||||
|
process = &process_;
|
||||||
applet_resource_user_id = applet_resource_user_id_;
|
applet_resource_user_id = applet_resource_user_id_;
|
||||||
session_id = session_id_;
|
session_id = session_id_;
|
||||||
|
|
||||||
@ -131,8 +132,7 @@ Result System::Initialize(const AudioRendererParameterInternal& params,
|
|||||||
render_device = params.rendering_device;
|
render_device = params.rendering_device;
|
||||||
execution_mode = params.execution_mode;
|
execution_mode = params.execution_mode;
|
||||||
|
|
||||||
process_handle->GetMemory().ZeroBlock(transfer_memory->GetSourceAddress(),
|
process->GetMemory().ZeroBlock(transfer_memory->GetSourceAddress(), transfer_memory_size);
|
||||||
transfer_memory_size);
|
|
||||||
|
|
||||||
// Note: We're not actually using the transfer memory because it's a pain to code for.
|
// Note: We're not actually using the transfer memory because it's a pain to code for.
|
||||||
// Allocate the memory normally instead and hope the game doesn't try to read anything back
|
// Allocate the memory normally instead and hope the game doesn't try to read anything back
|
||||||
@ -616,7 +616,7 @@ void System::SendCommandToDsp() {
|
|||||||
static_cast<u64>((time_limit_percent / 100) * 2'880'000.0 *
|
static_cast<u64>((time_limit_percent / 100) * 2'880'000.0 *
|
||||||
(static_cast<f32>(render_time_limit_percent) / 100.0f))};
|
(static_cast<f32>(render_time_limit_percent) / 100.0f))};
|
||||||
audio_renderer.SetCommandBuffer(session_id, translated_addr, command_size, time_limit,
|
audio_renderer.SetCommandBuffer(session_id, translated_addr, command_size, time_limit,
|
||||||
applet_resource_user_id, process_handle,
|
applet_resource_user_id, process,
|
||||||
reset_command_buffers);
|
reset_command_buffers);
|
||||||
reset_command_buffers = false;
|
reset_command_buffers = false;
|
||||||
command_buffer_size = command_size;
|
command_buffer_size = command_size;
|
||||||
|
@ -74,14 +74,14 @@ public:
|
|||||||
* @param params - Input parameters to initialize the system with.
|
* @param params - Input parameters to initialize the system with.
|
||||||
* @param transfer_memory - Game-supplied memory for all workbuffers. Unused.
|
* @param transfer_memory - Game-supplied memory for all workbuffers. Unused.
|
||||||
* @param transfer_memory_size - Size of the transfer memory. Unused.
|
* @param transfer_memory_size - Size of the transfer memory. Unused.
|
||||||
* @param process_handle - Process handle, also used for memory.
|
* @param process_handle - Process handle, also used for memory. Unused.
|
||||||
* @param applet_resource_user_id - Applet id for this renderer. Unused.
|
* @param applet_resource_user_id - Applet id for this renderer. Unused.
|
||||||
* @param session_id - Session id of this renderer.
|
* @param session_id - Session id of this renderer.
|
||||||
* @return Result code.
|
* @return Result code.
|
||||||
*/
|
*/
|
||||||
Result Initialize(const AudioRendererParameterInternal& params,
|
Result Initialize(const AudioRendererParameterInternal& params,
|
||||||
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
|
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
|
||||||
Kernel::KProcess* process_handle, u64 applet_resource_user_id,
|
u32 process_handle, Kernel::KProcess& process, u64 applet_resource_user_id,
|
||||||
s32 session_id);
|
s32 session_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -278,7 +278,9 @@ private:
|
|||||||
/// Does what locks do
|
/// Does what locks do
|
||||||
std::mutex lock{};
|
std::mutex lock{};
|
||||||
/// Process this audio render is operating within, used for memory reads/writes.
|
/// Process this audio render is operating within, used for memory reads/writes.
|
||||||
Kernel::KProcess* process_handle{};
|
Kernel::KProcess* process{};
|
||||||
|
/// Handle for the process for this system, unused
|
||||||
|
u32 process_handle{};
|
||||||
/// Applet resource id for this system, unused
|
/// Applet resource id for this system, unused
|
||||||
u64 applet_resource_user_id{};
|
u64 applet_resource_user_id{};
|
||||||
/// Controls performance input and output
|
/// Controls performance input and output
|
||||||
|
@ -357,9 +357,7 @@ bool IsCubebSuitable() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({ cubeb_destroy(ctx); });
|
||||||
cubeb_destroy(ctx);
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (SUCCEEDED(com_init_result)) {
|
if (SUCCEEDED(com_init_result)) {
|
||||||
|
@ -20,10 +20,10 @@
|
|||||||
namespace AudioCore::Sink {
|
namespace AudioCore::Sink {
|
||||||
|
|
||||||
void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) {
|
void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) {
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({
|
||||||
queue.enqueue(buffer);
|
queue.enqueue(buffer);
|
||||||
++queued_buffers;
|
++queued_buffers;
|
||||||
};
|
});
|
||||||
|
|
||||||
if (type == StreamType::In) {
|
if (type == StreamType::In) {
|
||||||
return;
|
return;
|
||||||
|
@ -20,9 +20,7 @@ std::string DemangleSymbol(const std::string& mangled) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
char* demangled = nullptr;
|
char* demangled = nullptr;
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({ std::free(demangled); });
|
||||||
std::free(demangled);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (is_itanium(mangled)) {
|
if (is_itanium(mangled)) {
|
||||||
demangled = llvm::itaniumDemangle(mangled.c_str());
|
demangled = llvm::itaniumDemangle(mangled.c_str());
|
||||||
|
@ -430,11 +430,11 @@ public:
|
|||||||
explicit Impl(size_t backing_size_, size_t virtual_size_)
|
explicit Impl(size_t backing_size_, size_t virtual_size_)
|
||||||
: backing_size{backing_size_}, virtual_size{virtual_size_} {
|
: backing_size{backing_size_}, virtual_size{virtual_size_} {
|
||||||
bool good = false;
|
bool good = false;
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({
|
||||||
if (!good) {
|
if (!good) {
|
||||||
Release();
|
Release();
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
long page_size = sysconf(_SC_PAGESIZE);
|
long page_size = sysconf(_SC_PAGESIZE);
|
||||||
if (page_size != 0x1000) {
|
if (page_size != 0x1000) {
|
||||||
|
@ -24,10 +24,10 @@ bool PageTable::ContinueTraversal(TraversalEntry* out_entry, TraversalContext* c
|
|||||||
out_entry->block_size = page_size;
|
out_entry->block_size = page_size;
|
||||||
|
|
||||||
// Regardless of whether the page was mapped, advance on exit.
|
// Regardless of whether the page was mapped, advance on exit.
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({
|
||||||
context->next_page += 1;
|
context->next_page += 1;
|
||||||
context->next_offset += page_size;
|
context->next_offset += page_size;
|
||||||
};
|
});
|
||||||
|
|
||||||
// Validate that we can read the actual entry.
|
// Validate that we can read the actual entry.
|
||||||
const auto page = context->next_page;
|
const auto page = context->next_page;
|
||||||
|
@ -7,61 +7,29 @@
|
|||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
template <class F>
|
template <typename Func>
|
||||||
class ScopeGuard {
|
struct ScopeExitHelper {
|
||||||
YUZU_NON_COPYABLE(ScopeGuard);
|
explicit ScopeExitHelper(Func&& func_) : func(std::move(func_)) {}
|
||||||
|
~ScopeExitHelper() {
|
||||||
private:
|
|
||||||
F f;
|
|
||||||
bool active;
|
|
||||||
|
|
||||||
public:
|
|
||||||
constexpr ScopeGuard(F f_) : f(std::move(f_)), active(true) {}
|
|
||||||
constexpr ~ScopeGuard() {
|
|
||||||
if (active) {
|
if (active) {
|
||||||
f();
|
func();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
constexpr void Cancel() {
|
|
||||||
|
void Cancel() {
|
||||||
active = false;
|
active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr ScopeGuard(ScopeGuard&& rhs) : f(std::move(rhs.f)), active(rhs.active) {
|
Func func;
|
||||||
rhs.Cancel();
|
bool active{true};
|
||||||
}
|
|
||||||
|
|
||||||
ScopeGuard& operator=(ScopeGuard&& rhs) = delete;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class F>
|
template <typename Func>
|
||||||
constexpr ScopeGuard<F> MakeScopeGuard(F f) {
|
ScopeExitHelper<Func> ScopeExit(Func&& func) {
|
||||||
return ScopeGuard<F>(std::move(f));
|
return ScopeExitHelper<Func>(std::forward<Func>(func));
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class ScopeGuardOnExit {};
|
|
||||||
|
|
||||||
template <typename F>
|
|
||||||
constexpr ScopeGuard<F> operator+(ScopeGuardOnExit, F&& f) {
|
|
||||||
return ScopeGuard<F>(std::forward<F>(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace detail
|
} // 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
|
* 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.
|
* for doing ad-hoc clean-up tasks in a function with multiple returns.
|
||||||
@ -70,7 +38,7 @@ constexpr ScopeGuard<F> operator+(ScopeGuardOnExit, F&& f) {
|
|||||||
* \code
|
* \code
|
||||||
* const int saved_val = g_foo;
|
* const int saved_val = g_foo;
|
||||||
* g_foo = 55;
|
* g_foo = 55;
|
||||||
* SCOPE_EXIT{ g_foo = saved_val; };
|
* SCOPE_EXIT({ g_foo = saved_val; });
|
||||||
*
|
*
|
||||||
* if (Bar()) {
|
* if (Bar()) {
|
||||||
* return 0;
|
* return 0;
|
||||||
@ -79,4 +47,10 @@ constexpr ScopeGuard<F> operator+(ScopeGuardOnExit, F&& f) {
|
|||||||
* }
|
* }
|
||||||
* \endcode
|
* \endcode
|
||||||
*/
|
*/
|
||||||
#define SCOPE_EXIT auto ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE_) = SCOPE_GUARD
|
#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)
|
||||||
|
@ -384,12 +384,6 @@ struct Values {
|
|||||||
AstcRecompression::Bc3,
|
AstcRecompression::Bc3,
|
||||||
"astc_recompression",
|
"astc_recompression",
|
||||||
Category::RendererAdvanced};
|
Category::RendererAdvanced};
|
||||||
SwitchableSetting<VramUsageMode, true> vram_usage_mode{linkage,
|
|
||||||
VramUsageMode::Conservative,
|
|
||||||
VramUsageMode::Conservative,
|
|
||||||
VramUsageMode::Aggressive,
|
|
||||||
"vram_usage_mode",
|
|
||||||
Category::RendererAdvanced};
|
|
||||||
SwitchableSetting<bool> async_presentation{linkage,
|
SwitchableSetting<bool> async_presentation{linkage,
|
||||||
#ifdef ANDROID
|
#ifdef ANDROID
|
||||||
true,
|
true,
|
||||||
|
@ -122,8 +122,6 @@ ENUM(AstcRecompression, Uncompressed, Bc1, Bc3);
|
|||||||
|
|
||||||
ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed);
|
ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed);
|
||||||
|
|
||||||
ENUM(VramUsageMode, Conservative, Aggressive);
|
|
||||||
|
|
||||||
ENUM(RendererBackend, OpenGL, Vulkan, Null);
|
ENUM(RendererBackend, OpenGL, Vulkan, Null);
|
||||||
|
|
||||||
ENUM(ShaderBackend, Glsl, Glasm, SpirV);
|
ENUM(ShaderBackend, Glsl, Glasm, SpirV);
|
||||||
|
@ -38,10 +38,6 @@ std::string StringFromBuffer(std::span<const u8> data) {
|
|||||||
return std::string(data.begin(), std::find(data.begin(), data.end(), '\0'));
|
return std::string(data.begin(), std::find(data.begin(), data.end(), '\0'));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string StringFromBuffer(std::span<const char> data) {
|
|
||||||
return std::string(data.begin(), std::find(data.begin(), data.end(), '\0'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Turns " hej " into "hej". Also handles tabs.
|
// Turns " hej " into "hej". Also handles tabs.
|
||||||
std::string StripSpaces(const std::string& str) {
|
std::string StripSpaces(const std::string& str) {
|
||||||
const std::size_t s = str.find_first_not_of(" \t\r\n");
|
const std::size_t s = str.find_first_not_of(" \t\r\n");
|
||||||
|
@ -19,7 +19,6 @@ namespace Common {
|
|||||||
[[nodiscard]] std::string ToUpper(std::string str);
|
[[nodiscard]] std::string ToUpper(std::string str);
|
||||||
|
|
||||||
[[nodiscard]] std::string StringFromBuffer(std::span<const u8> data);
|
[[nodiscard]] std::string StringFromBuffer(std::span<const u8> data);
|
||||||
[[nodiscard]] std::string StringFromBuffer(std::span<const char> data);
|
|
||||||
|
|
||||||
[[nodiscard]] std::string StripSpaces(const std::string& s);
|
[[nodiscard]] std::string StripSpaces(const std::string& s);
|
||||||
[[nodiscard]] std::string StripQuotes(const std::string& s);
|
[[nodiscard]] std::string StripQuotes(const std::string& s);
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
add_library(core STATIC
|
add_library(core STATIC
|
||||||
arm/arm_interface.cpp
|
|
||||||
arm/arm_interface.h
|
arm/arm_interface.h
|
||||||
|
arm/arm_interface.cpp
|
||||||
arm/debug.cpp
|
arm/debug.cpp
|
||||||
arm/debug.h
|
arm/debug.h
|
||||||
arm/exclusive_monitor.cpp
|
arm/exclusive_monitor.cpp
|
||||||
@ -37,10 +37,10 @@ add_library(core STATIC
|
|||||||
debugger/gdbstub.h
|
debugger/gdbstub.h
|
||||||
debugger/gdbstub_arch.cpp
|
debugger/gdbstub_arch.cpp
|
||||||
debugger/gdbstub_arch.h
|
debugger/gdbstub_arch.h
|
||||||
device_memory.cpp
|
|
||||||
device_memory.h
|
|
||||||
device_memory_manager.h
|
device_memory_manager.h
|
||||||
device_memory_manager.inc
|
device_memory_manager.inc
|
||||||
|
device_memory.cpp
|
||||||
|
device_memory.h
|
||||||
file_sys/bis_factory.cpp
|
file_sys/bis_factory.cpp
|
||||||
file_sys/bis_factory.h
|
file_sys/bis_factory.h
|
||||||
file_sys/card_image.cpp
|
file_sys/card_image.cpp
|
||||||
@ -58,14 +58,9 @@ add_library(core STATIC
|
|||||||
file_sys/fs_operate_range.h
|
file_sys/fs_operate_range.h
|
||||||
file_sys/fs_path.h
|
file_sys/fs_path.h
|
||||||
file_sys/fs_path_utility.h
|
file_sys/fs_path_utility.h
|
||||||
file_sys/fs_save_data_types.h
|
|
||||||
file_sys/fs_string_util.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.cpp
|
||||||
file_sys/fsmitm_romfsbuild.h
|
file_sys/fsmitm_romfsbuild.h
|
||||||
file_sys/fssrv/fssrv_sf_path.h
|
|
||||||
file_sys/fssystem/fs_i_storage.h
|
file_sys/fssystem/fs_i_storage.h
|
||||||
file_sys/fssystem/fs_types.h
|
file_sys/fssystem/fs_types.h
|
||||||
file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.cpp
|
file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.cpp
|
||||||
@ -395,20 +390,6 @@ add_library(core STATIC
|
|||||||
hle/service/acc/errors.h
|
hle/service/acc/errors.h
|
||||||
hle/service/acc/profile_manager.cpp
|
hle/service/acc/profile_manager.cpp
|
||||||
hle/service/acc/profile_manager.h
|
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.cpp
|
||||||
hle/service/am/frontend/applet_cabinet.h
|
hle/service/am/frontend/applet_cabinet.h
|
||||||
hle/service/am/frontend/applet_controller.cpp
|
hle/service/am/frontend/applet_controller.cpp
|
||||||
@ -430,6 +411,20 @@ add_library(core STATIC
|
|||||||
hle/service/am/frontend/applet_web_browser_types.h
|
hle/service/am/frontend/applet_web_browser_types.h
|
||||||
hle/service/am/frontend/applets.cpp
|
hle/service/am/frontend/applets.cpp
|
||||||
hle/service/am/frontend/applets.h
|
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/display_layer_manager.cpp
|
||||||
|
hle/service/am/display_layer_manager.h
|
||||||
hle/service/am/hid_registration.cpp
|
hle/service/am/hid_registration.cpp
|
||||||
hle/service/am/hid_registration.h
|
hle/service/am/hid_registration.h
|
||||||
hle/service/am/library_applet_storage.cpp
|
hle/service/am/library_applet_storage.cpp
|
||||||
@ -446,10 +441,10 @@ add_library(core STATIC
|
|||||||
hle/service/am/service/application_creator.h
|
hle/service/am/service/application_creator.h
|
||||||
hle/service/am/service/application_functions.cpp
|
hle/service/am/service/application_functions.cpp
|
||||||
hle/service/am/service/application_functions.h
|
hle/service/am/service/application_functions.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.cpp
|
||||||
hle/service/am/service/application_proxy_service.h
|
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/audio_controller.cpp
|
hle/service/am/service/audio_controller.cpp
|
||||||
hle/service/am/service/audio_controller.h
|
hle/service/am/service/audio_controller.h
|
||||||
hle/service/am/service/common_state_getter.cpp
|
hle/service/am/service/common_state_getter.cpp
|
||||||
@ -478,53 +473,53 @@ add_library(core STATIC
|
|||||||
hle/service/am/service/process_winding_controller.h
|
hle/service/am/service/process_winding_controller.h
|
||||||
hle/service/am/service/self_controller.cpp
|
hle/service/am/service/self_controller.cpp
|
||||||
hle/service/am/service/self_controller.h
|
hle/service/am/service/self_controller.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.cpp
|
||||||
hle/service/am/service/storage_accessor.h
|
hle/service/am/service/storage_accessor.h
|
||||||
|
hle/service/am/service/storage.cpp
|
||||||
|
hle/service/am/service/storage.h
|
||||||
hle/service/am/service/system_applet_proxy.cpp
|
hle/service/am/service/system_applet_proxy.cpp
|
||||||
hle/service/am/service/system_applet_proxy.h
|
hle/service/am/service/system_applet_proxy.h
|
||||||
hle/service/am/service/window_controller.cpp
|
hle/service/am/service/window_controller.cpp
|
||||||
hle/service/am/service/window_controller.h
|
hle/service/am/service/window_controller.h
|
||||||
hle/service/aoc/addon_content_manager.cpp
|
hle/service/aoc/aoc_u.cpp
|
||||||
hle/service/aoc/addon_content_manager.h
|
hle/service/aoc/aoc_u.h
|
||||||
hle/service/aoc/purchase_event_manager.cpp
|
|
||||||
hle/service/aoc/purchase_event_manager.h
|
|
||||||
hle/service/apm/apm.cpp
|
hle/service/apm/apm.cpp
|
||||||
hle/service/apm/apm.h
|
hle/service/apm/apm.h
|
||||||
hle/service/apm/apm_controller.cpp
|
hle/service/apm/apm_controller.cpp
|
||||||
hle/service/apm/apm_controller.h
|
hle/service/apm/apm_controller.h
|
||||||
hle/service/apm/apm_interface.cpp
|
hle/service/apm/apm_interface.cpp
|
||||||
hle/service/apm/apm_interface.h
|
hle/service/apm/apm_interface.h
|
||||||
hle/service/audio/audio_controller.cpp
|
hle/service/audio/audin_u.cpp
|
||||||
hle/service/audio/audio_controller.h
|
hle/service/audio/audin_u.h
|
||||||
hle/service/audio/audio_device.cpp
|
|
||||||
hle/service/audio/audio_device.h
|
|
||||||
hle/service/audio/audio_in_manager.cpp
|
|
||||||
hle/service/audio/audio_in_manager.h
|
|
||||||
hle/service/audio/audio_in.cpp
|
|
||||||
hle/service/audio/audio_in.h
|
|
||||||
hle/service/audio/audio_out_manager.cpp
|
|
||||||
hle/service/audio/audio_out_manager.h
|
|
||||||
hle/service/audio/audio_out.cpp
|
|
||||||
hle/service/audio/audio_out.h
|
|
||||||
hle/service/audio/audio_renderer_manager.cpp
|
|
||||||
hle/service/audio/audio_renderer_manager.h
|
|
||||||
hle/service/audio/audio_renderer.cpp
|
|
||||||
hle/service/audio/audio_renderer.h
|
|
||||||
hle/service/audio/audio.cpp
|
hle/service/audio/audio.cpp
|
||||||
hle/service/audio/audio.h
|
hle/service/audio/audio.h
|
||||||
|
hle/service/audio/audio_controller.cpp
|
||||||
|
hle/service/audio/audio_controller.h
|
||||||
|
hle/service/audio/audout_u.cpp
|
||||||
|
hle/service/audio/audout_u.h
|
||||||
|
hle/service/audio/audrec_a.cpp
|
||||||
|
hle/service/audio/audrec_a.h
|
||||||
|
hle/service/audio/audrec_u.cpp
|
||||||
|
hle/service/audio/audrec_u.h
|
||||||
|
hle/service/audio/audren_u.cpp
|
||||||
|
hle/service/audio/audren_u.h
|
||||||
hle/service/audio/errors.h
|
hle/service/audio/errors.h
|
||||||
hle/service/audio/final_output_recorder_manager_for_applet.cpp
|
hle/service/audio/hwopus.cpp
|
||||||
hle/service/audio/final_output_recorder_manager_for_applet.h
|
hle/service/audio/hwopus.h
|
||||||
hle/service/audio/final_output_recorder_manager.cpp
|
|
||||||
hle/service/audio/final_output_recorder_manager.h
|
|
||||||
hle/service/audio/hardware_opus_decoder_manager.cpp
|
|
||||||
hle/service/audio/hardware_opus_decoder_manager.h
|
|
||||||
hle/service/audio/hardware_opus_decoder.cpp
|
|
||||||
hle/service/audio/hardware_opus_decoder.h
|
|
||||||
hle/service/bcat/backend/backend.cpp
|
hle/service/bcat/backend/backend.cpp
|
||||||
hle/service/bcat/backend/backend.h
|
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.cpp
|
||||||
hle/service/bcat/bcat.h
|
hle/service/bcat/bcat.h
|
||||||
hle/service/bcat/bcat_result.h
|
hle/service/bcat/bcat_result.h
|
||||||
@ -540,18 +535,6 @@ add_library(core STATIC
|
|||||||
hle/service/bcat/delivery_cache_progress_service.h
|
hle/service/bcat/delivery_cache_progress_service.h
|
||||||
hle/service/bcat/delivery_cache_storage_service.cpp
|
hle/service/bcat/delivery_cache_storage_service.cpp
|
||||||
hle/service/bcat/delivery_cache_storage_service.h
|
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.cpp
|
||||||
hle/service/bcat/service_creator.h
|
hle/service/bcat/service_creator.h
|
||||||
hle/service/bpc/bpc.cpp
|
hle/service/bpc/bpc.cpp
|
||||||
@ -612,10 +595,6 @@ add_library(core STATIC
|
|||||||
hle/service/filesystem/fsp/fs_i_file.h
|
hle/service/filesystem/fsp/fs_i_file.h
|
||||||
hle/service/filesystem/fsp/fs_i_filesystem.cpp
|
hle/service/filesystem/fsp/fs_i_filesystem.cpp
|
||||||
hle/service/filesystem/fsp/fs_i_filesystem.h
|
hle/service/filesystem/fsp/fs_i_filesystem.h
|
||||||
hle/service/filesystem/fsp/fs_i_multi_commit_manager.cpp
|
|
||||||
hle/service/filesystem/fsp/fs_i_multi_commit_manager.h
|
|
||||||
hle/service/filesystem/fsp/fs_i_save_data_info_reader.cpp
|
|
||||||
hle/service/filesystem/fsp/fs_i_save_data_info_reader.h
|
|
||||||
hle/service/filesystem/fsp/fs_i_storage.cpp
|
hle/service/filesystem/fsp/fs_i_storage.cpp
|
||||||
hle/service/filesystem/fsp/fs_i_storage.h
|
hle/service/filesystem/fsp/fs_i_storage.h
|
||||||
hle/service/filesystem/fsp/fsp_ldr.cpp
|
hle/service/filesystem/fsp/fsp_ldr.cpp
|
||||||
@ -624,11 +603,13 @@ add_library(core STATIC
|
|||||||
hle/service/filesystem/fsp/fsp_pr.h
|
hle/service/filesystem/fsp/fsp_pr.h
|
||||||
hle/service/filesystem/fsp/fsp_srv.cpp
|
hle/service/filesystem/fsp/fsp_srv.cpp
|
||||||
hle/service/filesystem/fsp/fsp_srv.h
|
hle/service/filesystem/fsp/fsp_srv.h
|
||||||
hle/service/filesystem/fsp/fsp_types.h
|
hle/service/filesystem/fsp/fsp_util.h
|
||||||
hle/service/filesystem/romfs_controller.cpp
|
hle/service/filesystem/romfs_controller.cpp
|
||||||
hle/service/filesystem/romfs_controller.h
|
hle/service/filesystem/romfs_controller.h
|
||||||
hle/service/filesystem/save_data_controller.cpp
|
hle/service/filesystem/save_data_controller.cpp
|
||||||
hle/service/filesystem/save_data_controller.h
|
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.cpp
|
||||||
hle/service/friend/friend.h
|
hle/service/friend/friend.h
|
||||||
hle/service/friend/friend_interface.cpp
|
hle/service/friend/friend_interface.cpp
|
||||||
@ -788,10 +769,10 @@ add_library(core STATIC
|
|||||||
hle/service/ns/factory_reset_interface.h
|
hle/service/ns/factory_reset_interface.h
|
||||||
hle/service/ns/language.cpp
|
hle/service/ns/language.cpp
|
||||||
hle/service/ns/language.h
|
hle/service/ns/language.h
|
||||||
hle/service/ns/ns.cpp
|
|
||||||
hle/service/ns/ns.h
|
|
||||||
hle/service/ns/ns_results.h
|
hle/service/ns/ns_results.h
|
||||||
hle/service/ns/ns_types.h
|
hle/service/ns/ns_types.h
|
||||||
|
hle/service/ns/ns.cpp
|
||||||
|
hle/service/ns/ns.h
|
||||||
hle/service/ns/platform_service_manager.cpp
|
hle/service/ns/platform_service_manager.cpp
|
||||||
hle/service/ns/platform_service_manager.h
|
hle/service/ns/platform_service_manager.h
|
||||||
hle/service/ns/query_service.cpp
|
hle/service/ns/query_service.cpp
|
||||||
@ -862,12 +843,12 @@ add_library(core STATIC
|
|||||||
hle/service/nvnflinger/consumer_listener.h
|
hle/service/nvnflinger/consumer_listener.h
|
||||||
hle/service/nvnflinger/graphic_buffer_producer.cpp
|
hle/service/nvnflinger/graphic_buffer_producer.cpp
|
||||||
hle/service/nvnflinger/graphic_buffer_producer.h
|
hle/service/nvnflinger/graphic_buffer_producer.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.cpp
|
||||||
hle/service/nvnflinger/hos_binder_driver_server.h
|
hle/service/nvnflinger/hos_binder_driver_server.h
|
||||||
|
hle/service/nvnflinger/hos_binder_driver.cpp
|
||||||
|
hle/service/nvnflinger/hos_binder_driver.h
|
||||||
|
hle/service/nvnflinger/hardware_composer.cpp
|
||||||
|
hle/service/nvnflinger/hardware_composer.h
|
||||||
hle/service/nvnflinger/hwc_layer.h
|
hle/service/nvnflinger/hwc_layer.h
|
||||||
hle/service/nvnflinger/nvnflinger.cpp
|
hle/service/nvnflinger/nvnflinger.cpp
|
||||||
hle/service/nvnflinger/nvnflinger.h
|
hle/service/nvnflinger/nvnflinger.h
|
||||||
@ -881,20 +862,8 @@ add_library(core STATIC
|
|||||||
hle/service/nvnflinger/ui/graphic_buffer.cpp
|
hle/service/nvnflinger/ui/graphic_buffer.cpp
|
||||||
hle/service/nvnflinger/ui/graphic_buffer.h
|
hle/service/nvnflinger/ui/graphic_buffer.h
|
||||||
hle/service/nvnflinger/window.h
|
hle/service/nvnflinger/window.h
|
||||||
hle/service/olsc/daemon_controller.cpp
|
|
||||||
hle/service/olsc/daemon_controller.h
|
|
||||||
hle/service/olsc/native_handle_holder.cpp
|
|
||||||
hle/service/olsc/native_handle_holder.h
|
|
||||||
hle/service/olsc/olsc_service_for_application.cpp
|
|
||||||
hle/service/olsc/olsc_service_for_application.h
|
|
||||||
hle/service/olsc/olsc_service_for_system_service.cpp
|
|
||||||
hle/service/olsc/olsc_service_for_system_service.h
|
|
||||||
hle/service/olsc/olsc.cpp
|
hle/service/olsc/olsc.cpp
|
||||||
hle/service/olsc/olsc.h
|
hle/service/olsc/olsc.h
|
||||||
hle/service/olsc/remote_storage_controller.cpp
|
|
||||||
hle/service/olsc/remote_storage_controller.h
|
|
||||||
hle/service/olsc/transfer_task_list_controller.cpp
|
|
||||||
hle/service/olsc/transfer_task_list_controller.h
|
|
||||||
hle/service/omm/omm.cpp
|
hle/service/omm/omm.cpp
|
||||||
hle/service/omm/omm.h
|
hle/service/omm/omm.h
|
||||||
hle/service/omm/operation_mode_manager.cpp
|
hle/service/omm/operation_mode_manager.cpp
|
||||||
@ -905,44 +874,25 @@ add_library(core STATIC
|
|||||||
hle/service/omm/power_state_interface.h
|
hle/service/omm/power_state_interface.h
|
||||||
hle/service/os/event.cpp
|
hle/service/os/event.cpp
|
||||||
hle/service/os/event.h
|
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.cpp
|
||||||
hle/service/os/multi_wait_holder.h
|
hle/service/os/multi_wait_holder.h
|
||||||
hle/service/os/multi_wait_utils.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.cpp
|
||||||
hle/service/os/mutex.h
|
hle/service/os/mutex.h
|
||||||
hle/service/pcie/pcie.cpp
|
hle/service/pcie/pcie.cpp
|
||||||
hle/service/pcie/pcie.h
|
hle/service/pcie/pcie.h
|
||||||
hle/service/pctl/parental_control_service_factory.cpp
|
|
||||||
hle/service/pctl/parental_control_service_factory.h
|
|
||||||
hle/service/pctl/parental_control_service.cpp
|
|
||||||
hle/service/pctl/parental_control_service.h
|
|
||||||
hle/service/pctl/pctl.cpp
|
hle/service/pctl/pctl.cpp
|
||||||
hle/service/pctl/pctl.h
|
hle/service/pctl/pctl.h
|
||||||
hle/service/pctl/pctl_results.h
|
hle/service/pctl/pctl_module.cpp
|
||||||
hle/service/pctl/pctl_types.h
|
hle/service/pctl/pctl_module.h
|
||||||
hle/service/pcv/pcv.cpp
|
hle/service/pcv/pcv.cpp
|
||||||
hle/service/pcv/pcv.h
|
hle/service/pcv/pcv.h
|
||||||
hle/service/pm/pm.cpp
|
hle/service/pm/pm.cpp
|
||||||
hle/service/pm/pm.h
|
hle/service/pm/pm.h
|
||||||
hle/service/prepo/prepo.cpp
|
hle/service/prepo/prepo.cpp
|
||||||
hle/service/prepo/prepo.h
|
hle/service/prepo/prepo.h
|
||||||
hle/service/psc/ovln/ovln_types.h
|
|
||||||
hle/service/psc/ovln/receiver_service.cpp
|
|
||||||
hle/service/psc/ovln/receiver_service.h
|
|
||||||
hle/service/psc/ovln/receiver.cpp
|
|
||||||
hle/service/psc/ovln/receiver.h
|
|
||||||
hle/service/psc/ovln/sender_service.cpp
|
|
||||||
hle/service/psc/ovln/sender_service.h
|
|
||||||
hle/service/psc/ovln/sender.cpp
|
|
||||||
hle/service/psc/ovln/sender.h
|
|
||||||
hle/service/psc/pm_control.cpp
|
|
||||||
hle/service/psc/pm_control.h
|
|
||||||
hle/service/psc/pm_module.cpp
|
|
||||||
hle/service/psc/pm_module.h
|
|
||||||
hle/service/psc/pm_service.cpp
|
|
||||||
hle/service/psc/pm_service.h
|
|
||||||
hle/service/psc/psc.cpp
|
hle/service/psc/psc.cpp
|
||||||
hle/service/psc/psc.h
|
hle/service/psc/psc.h
|
||||||
hle/service/psc/time/alarms.cpp
|
hle/service/psc/time/alarms.cpp
|
||||||
@ -966,17 +916,15 @@ add_library(core STATIC
|
|||||||
hle/service/psc/time/common.cpp
|
hle/service/psc/time/common.cpp
|
||||||
hle/service/psc/time/common.h
|
hle/service/psc/time/common.h
|
||||||
hle/service/psc/time/errors.h
|
hle/service/psc/time/errors.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.cpp
|
||||||
hle/service/psc/time/shared_memory.h
|
hle/service/psc/time/shared_memory.h
|
||||||
hle/service/psc/time/static.cpp
|
hle/service/psc/time/static.cpp
|
||||||
hle/service/psc/time/static.h
|
hle/service/psc/time/static.h
|
||||||
|
hle/service/psc/time/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/steady_clock.cpp
|
hle/service/psc/time/steady_clock.cpp
|
||||||
hle/service/psc/time/steady_clock.h
|
hle/service/psc/time/steady_clock.h
|
||||||
hle/service/psc/time/system_clock.cpp
|
hle/service/psc/time/system_clock.cpp
|
||||||
@ -985,6 +933,8 @@ add_library(core STATIC
|
|||||||
hle/service/psc/time/time_zone.h
|
hle/service/psc/time/time_zone.h
|
||||||
hle/service/psc/time/time_zone_service.cpp
|
hle/service/psc/time/time_zone_service.cpp
|
||||||
hle/service/psc/time/time_zone_service.h
|
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.cpp
|
||||||
hle/service/ptm/psm.h
|
hle/service/ptm/psm.h
|
||||||
hle/service/ptm/ptm.cpp
|
hle/service/ptm/ptm.cpp
|
||||||
@ -1003,19 +953,19 @@ add_library(core STATIC
|
|||||||
hle/service/service.h
|
hle/service/service.h
|
||||||
hle/service/services.cpp
|
hle/service/services.cpp
|
||||||
hle/service/services.h
|
hle/service/services.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/set/factory_settings_server.cpp
|
hle/service/set/factory_settings_server.cpp
|
||||||
hle/service/set/factory_settings_server.h
|
hle/service/set/factory_settings_server.h
|
||||||
hle/service/set/firmware_debug_settings_server.cpp
|
hle/service/set/firmware_debug_settings_server.cpp
|
||||||
hle/service/set/firmware_debug_settings_server.h
|
hle/service/set/firmware_debug_settings_server.h
|
||||||
hle/service/set/key_code_map.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.cpp
|
||||||
hle/service/set/settings.h
|
hle/service/set/settings.h
|
||||||
hle/service/set/settings_server.cpp
|
hle/service/set/settings_server.cpp
|
||||||
@ -1058,10 +1008,10 @@ add_library(core STATIC
|
|||||||
hle/service/vi/conductor.h
|
hle/service/vi/conductor.h
|
||||||
hle/service/vi/container.cpp
|
hle/service/vi/container.cpp
|
||||||
hle/service/vi/container.h
|
hle/service/vi/container.h
|
||||||
hle/service/vi/display.h
|
|
||||||
hle/service/vi/display_list.h
|
hle/service/vi/display_list.h
|
||||||
hle/service/vi/layer.h
|
hle/service/vi/display.h
|
||||||
hle/service/vi/layer_list.h
|
hle/service/vi/layer_list.h
|
||||||
|
hle/service/vi/layer.h
|
||||||
hle/service/vi/manager_display_service.cpp
|
hle/service/vi/manager_display_service.cpp
|
||||||
hle/service/vi/manager_display_service.h
|
hle/service/vi/manager_display_service.h
|
||||||
hle/service/vi/manager_root_service.cpp
|
hle/service/vi/manager_root_service.cpp
|
||||||
@ -1074,10 +1024,10 @@ add_library(core STATIC
|
|||||||
hle/service/vi/system_display_service.h
|
hle/service/vi/system_display_service.h
|
||||||
hle/service/vi/system_root_service.cpp
|
hle/service/vi/system_root_service.cpp
|
||||||
hle/service/vi/system_root_service.h
|
hle/service/vi/system_root_service.h
|
||||||
hle/service/vi/vi.cpp
|
|
||||||
hle/service/vi/vi.h
|
|
||||||
hle/service/vi/vi_results.h
|
hle/service/vi/vi_results.h
|
||||||
hle/service/vi/vi_types.h
|
hle/service/vi/vi_types.h
|
||||||
|
hle/service/vi/vi.cpp
|
||||||
|
hle/service/vi/vi.h
|
||||||
hle/service/vi/vsync_manager.cpp
|
hle/service/vi/vsync_manager.cpp
|
||||||
hle/service/vi/vsync_manager.h
|
hle/service/vi/vsync_manager.h
|
||||||
internal_network/network.cpp
|
internal_network/network.cpp
|
||||||
|
@ -199,10 +199,10 @@ void CpuManager::RunThread(std::stop_token token, std::size_t core) {
|
|||||||
data.host_context = Common::Fiber::ThreadToFiber();
|
data.host_context = Common::Fiber::ThreadToFiber();
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({
|
||||||
data.host_context->Exit();
|
data.host_context->Exit();
|
||||||
MicroProfileOnThreadExit();
|
MicroProfileOnThreadExit();
|
||||||
};
|
});
|
||||||
|
|
||||||
// Running
|
// Running
|
||||||
if (!gpu_barrier->Sync(token)) {
|
if (!gpu_barrier->Sync(token)) {
|
||||||
|
@ -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);
|
std::min((next_pages << Memory::YUZU_PAGEBITS) - page_offset, remaining_size);
|
||||||
const auto current_vaddr =
|
const auto current_vaddr =
|
||||||
static_cast<u64>((page_index << Memory::YUZU_PAGEBITS) + page_offset);
|
static_cast<u64>((page_index << Memory::YUZU_PAGEBITS) + page_offset);
|
||||||
SCOPE_EXIT{
|
SCOPE_EXIT({
|
||||||
page_index += next_pages;
|
page_index += next_pages;
|
||||||
page_offset = 0;
|
page_offset = 0;
|
||||||
increment(copy_amount);
|
increment(copy_amount);
|
||||||
remaining_size -= copy_amount;
|
remaining_size -= copy_amount;
|
||||||
};
|
});
|
||||||
|
|
||||||
auto phys_addr = compressed_physical_ptr[page_index];
|
auto phys_addr = compressed_physical_ptr[page_index];
|
||||||
if (phys_addr == 0) {
|
if (phys_addr == 0) {
|
||||||
|
@ -3,10 +3,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string_view>
|
|
||||||
#include "common/common_funcs.h"
|
|
||||||
#include "common/common_types.h"
|
|
||||||
|
|
||||||
namespace FileSys {
|
namespace FileSys {
|
||||||
|
|
||||||
constexpr inline size_t EntryNameLengthMax = 0x300;
|
constexpr inline size_t EntryNameLengthMax = 0x300;
|
||||||
|
@ -23,8 +23,6 @@ enum class OpenDirectoryMode : u64 {
|
|||||||
File = (1 << 1),
|
File = (1 << 1),
|
||||||
|
|
||||||
All = (Directory | File),
|
All = (Directory | File),
|
||||||
|
|
||||||
NotRequireFileSize = (1ULL << 31),
|
|
||||||
};
|
};
|
||||||
DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode)
|
DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode)
|
||||||
|
|
||||||
@ -38,29 +36,4 @@ enum class CreateOption : u8 {
|
|||||||
BigFile = (1 << 0),
|
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
|
} // namespace FileSys
|
||||||
|
@ -10,7 +10,7 @@ namespace FileSys {
|
|||||||
|
|
||||||
constexpr size_t RequiredAlignment = alignof(u64);
|
constexpr size_t RequiredAlignment = alignof(u64);
|
||||||
|
|
||||||
inline void* AllocateUnsafe(size_t size) {
|
void* AllocateUnsafe(size_t size) {
|
||||||
// Allocate
|
// Allocate
|
||||||
void* const ptr = ::operator new(size, std::align_val_t{RequiredAlignment});
|
void* const ptr = ::operator new(size, std::align_val_t{RequiredAlignment});
|
||||||
|
|
||||||
@ -21,16 +21,16 @@ inline void* AllocateUnsafe(size_t size) {
|
|||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void DeallocateUnsafe(void* ptr, size_t size) {
|
void DeallocateUnsafe(void* ptr, size_t size) {
|
||||||
// Deallocate the pointer
|
// Deallocate the pointer
|
||||||
::operator delete(ptr, std::align_val_t{RequiredAlignment});
|
::operator delete(ptr, std::align_val_t{RequiredAlignment});
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void* Allocate(size_t size) {
|
void* Allocate(size_t size) {
|
||||||
return AllocateUnsafe(size);
|
return AllocateUnsafe(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Deallocate(void* ptr, size_t size) {
|
void Deallocate(void* ptr, size_t size) {
|
||||||
// If the pointer is non-null, deallocate it
|
// If the pointer is non-null, deallocate it
|
||||||
if (ptr != nullptr) {
|
if (ptr != nullptr) {
|
||||||
DeallocateUnsafe(ptr, size);
|
DeallocateUnsafe(ptr, size);
|
||||||
|
@ -381,7 +381,7 @@ public:
|
|||||||
|
|
||||||
// Check that it's possible for us to remove a child
|
// Check that it's possible for us to remove a child
|
||||||
auto* p = m_write_buffer.Get();
|
auto* p = m_write_buffer.Get();
|
||||||
s32 len = static_cast<s32>(std::strlen(p));
|
s32 len = std::strlen(p);
|
||||||
R_UNLESS(len != 1 || (p[0] != '/' && p[0] != '.'), ResultNotImplemented);
|
R_UNLESS(len != 1 || (p[0] != '/' && p[0] != '.'), ResultNotImplemented);
|
||||||
|
|
||||||
// Handle a trailing separator
|
// Handle a trailing separator
|
||||||
|
@ -426,9 +426,8 @@ public:
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr Result Normalize(char* dst, size_t* out_len, const char* path,
|
static Result Normalize(char* dst, size_t* out_len, const char* path, size_t max_out_size,
|
||||||
size_t max_out_size, bool is_windows_path,
|
bool is_windows_path, bool is_drive_relative_path,
|
||||||
bool is_drive_relative_path,
|
|
||||||
bool allow_all_characters = false) {
|
bool allow_all_characters = false) {
|
||||||
// Use StringTraits names for remainder of scope
|
// Use StringTraits names for remainder of scope
|
||||||
using namespace StringTraits;
|
using namespace StringTraits;
|
||||||
@ -448,7 +447,7 @@ public:
|
|||||||
char* replacement_path = nullptr;
|
char* replacement_path = nullptr;
|
||||||
size_t replacement_path_size = 0;
|
size_t replacement_path_size = 0;
|
||||||
|
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({
|
||||||
if (replacement_path != nullptr) {
|
if (replacement_path != nullptr) {
|
||||||
if (std::is_constant_evaluated()) {
|
if (std::is_constant_evaluated()) {
|
||||||
delete[] replacement_path;
|
delete[] replacement_path;
|
||||||
@ -456,7 +455,7 @@ public:
|
|||||||
Deallocate(replacement_path, replacement_path_size);
|
Deallocate(replacement_path, replacement_path_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
// Perform path replacement, if necessary
|
// Perform path replacement, if necessary
|
||||||
if (IsParentDirectoryPathReplacementNeeded(cur_path)) {
|
if (IsParentDirectoryPathReplacementNeeded(cur_path)) {
|
||||||
@ -1103,7 +1102,7 @@ public:
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr Result Normalize(char* dst, size_t dst_size, const char* path, size_t path_len,
|
static Result Normalize(char* dst, size_t dst_size, const char* path, size_t path_len,
|
||||||
const PathFlags& flags) {
|
const PathFlags& flags) {
|
||||||
// Use StringTraits names for remainder of scope
|
// Use StringTraits names for remainder of scope
|
||||||
using namespace StringTraits;
|
using namespace StringTraits;
|
||||||
@ -1200,7 +1199,7 @@ public:
|
|||||||
const size_t replaced_src_len = path_len - (src - path);
|
const size_t replaced_src_len = path_len - (src - path);
|
||||||
|
|
||||||
char* replaced_src = nullptr;
|
char* replaced_src = nullptr;
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({
|
||||||
if (replaced_src != nullptr) {
|
if (replaced_src != nullptr) {
|
||||||
if (std::is_constant_evaluated()) {
|
if (std::is_constant_evaluated()) {
|
||||||
delete[] replaced_src;
|
delete[] replaced_src;
|
||||||
@ -1208,7 +1207,7 @@ public:
|
|||||||
Deallocate(replaced_src, replaced_src_len);
|
Deallocate(replaced_src, replaced_src_len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
if (std::is_constant_evaluated()) {
|
if (std::is_constant_evaluated()) {
|
||||||
replaced_src = new char[replaced_src_len];
|
replaced_src = new char[replaced_src_len];
|
||||||
|
@ -1,175 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <fmt/format.h>
|
|
||||||
#include "common/common_funcs.h"
|
|
||||||
#include "common/common_types.h"
|
|
||||||
|
|
||||||
namespace FileSys {
|
|
||||||
|
|
||||||
using SaveDataId = u64;
|
|
||||||
using SystemSaveDataId = u64;
|
|
||||||
using SystemBcatSaveDataId = SystemSaveDataId;
|
|
||||||
using ProgramId = u64;
|
|
||||||
|
|
||||||
enum class SaveDataSpaceId : u8 {
|
|
||||||
System = 0,
|
|
||||||
User = 1,
|
|
||||||
SdSystem = 2,
|
|
||||||
Temporary = 3,
|
|
||||||
SdUser = 4,
|
|
||||||
|
|
||||||
ProperSystem = 100,
|
|
||||||
SafeMode = 101,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class SaveDataType : u8 {
|
|
||||||
System = 0,
|
|
||||||
Account = 1,
|
|
||||||
Bcat = 2,
|
|
||||||
Device = 3,
|
|
||||||
Temporary = 4,
|
|
||||||
Cache = 5,
|
|
||||||
SystemBcat = 6,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class SaveDataRank : u8 {
|
|
||||||
Primary = 0,
|
|
||||||
Secondary = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SaveDataSize {
|
|
||||||
u64 normal;
|
|
||||||
u64 journal;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(SaveDataSize) == 0x10, "SaveDataSize has invalid size.");
|
|
||||||
|
|
||||||
using UserId = u128;
|
|
||||||
static_assert(std::is_trivially_copyable_v<UserId>, "Data type must be trivially copyable.");
|
|
||||||
static_assert(sizeof(UserId) == 0x10, "UserId has invalid size.");
|
|
||||||
|
|
||||||
constexpr inline SystemSaveDataId InvalidSystemSaveDataId = 0;
|
|
||||||
constexpr inline UserId InvalidUserId = {};
|
|
||||||
|
|
||||||
enum class SaveDataFlags : u32 {
|
|
||||||
None = (0 << 0),
|
|
||||||
KeepAfterResettingSystemSaveData = (1 << 0),
|
|
||||||
KeepAfterRefurbishment = (1 << 1),
|
|
||||||
KeepAfterResettingSystemSaveDataWithoutUserSaveData = (1 << 2),
|
|
||||||
NeedsSecureDelete = (1 << 3),
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class SaveDataMetaType : u8 {
|
|
||||||
None = 0,
|
|
||||||
Thumbnail = 1,
|
|
||||||
ExtensionContext = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SaveDataMetaInfo {
|
|
||||||
u32 size;
|
|
||||||
SaveDataMetaType type;
|
|
||||||
INSERT_PADDING_BYTES(0xB);
|
|
||||||
};
|
|
||||||
static_assert(std::is_trivially_copyable_v<SaveDataMetaInfo>,
|
|
||||||
"Data type must be trivially copyable.");
|
|
||||||
static_assert(sizeof(SaveDataMetaInfo) == 0x10, "SaveDataMetaInfo has invalid size.");
|
|
||||||
|
|
||||||
struct SaveDataCreationInfo {
|
|
||||||
s64 size;
|
|
||||||
s64 journal_size;
|
|
||||||
s64 block_size;
|
|
||||||
u64 owner_id;
|
|
||||||
u32 flags;
|
|
||||||
SaveDataSpaceId space_id;
|
|
||||||
bool pseudo;
|
|
||||||
INSERT_PADDING_BYTES(0x1A);
|
|
||||||
};
|
|
||||||
static_assert(std::is_trivially_copyable_v<SaveDataCreationInfo>,
|
|
||||||
"Data type must be trivially copyable.");
|
|
||||||
static_assert(sizeof(SaveDataCreationInfo) == 0x40, "SaveDataCreationInfo has invalid size.");
|
|
||||||
|
|
||||||
struct SaveDataAttribute {
|
|
||||||
ProgramId program_id;
|
|
||||||
UserId user_id;
|
|
||||||
SystemSaveDataId system_save_data_id;
|
|
||||||
SaveDataType type;
|
|
||||||
SaveDataRank rank;
|
|
||||||
u16 index;
|
|
||||||
INSERT_PADDING_BYTES(0x1C);
|
|
||||||
|
|
||||||
static constexpr SaveDataAttribute Make(ProgramId program_id, SaveDataType type, UserId user_id,
|
|
||||||
SystemSaveDataId system_save_data_id, u16 index,
|
|
||||||
SaveDataRank rank) {
|
|
||||||
return {
|
|
||||||
.program_id = program_id,
|
|
||||||
.user_id = user_id,
|
|
||||||
.system_save_data_id = system_save_data_id,
|
|
||||||
.type = type,
|
|
||||||
.rank = rank,
|
|
||||||
.index = index,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr SaveDataAttribute Make(ProgramId program_id, SaveDataType type, UserId user_id,
|
|
||||||
SystemSaveDataId system_save_data_id, u16 index) {
|
|
||||||
return Make(program_id, type, user_id, system_save_data_id, index, SaveDataRank::Primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr SaveDataAttribute Make(ProgramId program_id, SaveDataType type, UserId user_id,
|
|
||||||
SystemSaveDataId system_save_data_id) {
|
|
||||||
return Make(program_id, type, user_id, system_save_data_id, 0, SaveDataRank::Primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string DebugInfo() const {
|
|
||||||
return fmt::format(
|
|
||||||
"[title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}, type={:02X}, "
|
|
||||||
"rank={}, index={}]",
|
|
||||||
program_id, user_id[1], user_id[0], system_save_data_id, static_cast<u8>(type),
|
|
||||||
static_cast<u8>(rank), index);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
static_assert(sizeof(SaveDataAttribute) == 0x40);
|
|
||||||
static_assert(std::is_trivially_destructible<SaveDataAttribute>::value);
|
|
||||||
|
|
||||||
constexpr inline bool operator<(const SaveDataAttribute& lhs, const SaveDataAttribute& rhs) {
|
|
||||||
return std::tie(lhs.program_id, lhs.user_id, lhs.system_save_data_id, lhs.index, lhs.rank) <
|
|
||||||
std::tie(rhs.program_id, rhs.user_id, rhs.system_save_data_id, rhs.index, rhs.rank);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr inline bool operator==(const SaveDataAttribute& lhs, const SaveDataAttribute& rhs) {
|
|
||||||
return std::tie(lhs.program_id, lhs.user_id, lhs.system_save_data_id, lhs.type, lhs.rank,
|
|
||||||
lhs.index) == std::tie(rhs.program_id, rhs.user_id, rhs.system_save_data_id,
|
|
||||||
rhs.type, rhs.rank, rhs.index);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr inline bool operator!=(const SaveDataAttribute& lhs, const SaveDataAttribute& rhs) {
|
|
||||||
return !(lhs == rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SaveDataExtraData {
|
|
||||||
SaveDataAttribute attr;
|
|
||||||
u64 owner_id;
|
|
||||||
s64 timestamp;
|
|
||||||
u32 flags;
|
|
||||||
INSERT_PADDING_BYTES(4);
|
|
||||||
s64 available_size;
|
|
||||||
s64 journal_size;
|
|
||||||
s64 commit_id;
|
|
||||||
INSERT_PADDING_BYTES(0x190);
|
|
||||||
};
|
|
||||||
static_assert(sizeof(SaveDataExtraData) == 0x200, "SaveDataExtraData has invalid size.");
|
|
||||||
static_assert(std::is_trivially_copyable_v<SaveDataExtraData>,
|
|
||||||
"Data type must be trivially copyable.");
|
|
||||||
|
|
||||||
struct HashSalt {
|
|
||||||
static constexpr size_t Size = 32;
|
|
||||||
|
|
||||||
std::array<u8, Size> value;
|
|
||||||
};
|
|
||||||
static_assert(std::is_trivially_copyable_v<HashSalt>, "Data type must be trivially copyable.");
|
|
||||||
static_assert(sizeof(HashSalt) == HashSalt::Size);
|
|
||||||
|
|
||||||
} // namespace FileSys
|
|
@ -19,11 +19,6 @@ constexpr int Strlen(const T* str) {
|
|||||||
return length;
|
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>
|
template <typename T>
|
||||||
constexpr int Strnlen(const T* str, int count) {
|
constexpr int Strnlen(const T* str, int count) {
|
||||||
ASSERT(str != nullptr);
|
ASSERT(str != nullptr);
|
||||||
@ -37,11 +32,6 @@ constexpr int Strnlen(const T* str, int count) {
|
|||||||
return length;
|
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>
|
template <typename T>
|
||||||
constexpr int Strncmp(const T* lhs, const T* rhs, int count) {
|
constexpr int Strncmp(const T* lhs, const T* rhs, int count) {
|
||||||
ASSERT(lhs != nullptr);
|
ASSERT(lhs != nullptr);
|
||||||
@ -61,11 +51,6 @@ constexpr int Strncmp(const T* lhs, const T* rhs, int count) {
|
|||||||
return l - r;
|
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>
|
template <typename T>
|
||||||
static constexpr int Strlcpy(T* dst, const T* src, int count) {
|
static constexpr int Strlcpy(T* dst, const T* src, int count) {
|
||||||
ASSERT(dst != nullptr);
|
ASSERT(dst != nullptr);
|
||||||
|
@ -1,91 +0,0 @@
|
|||||||
// 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
|
|
@ -1,167 +0,0 @@
|
|||||||
// 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
|
|
@ -1,206 +0,0 @@
|
|||||||
// 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
|
|
@ -1,36 +0,0 @@
|
|||||||
// 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,7 +3,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <mutex>
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
#include "core/crypto/aes_util.h"
|
#include "core/crypto/aes_util.h"
|
||||||
|
@ -36,9 +36,7 @@ Result HierarchicalSha256Storage::Initialize(VirtualFile* base_storages, s32 lay
|
|||||||
// Get the base storage size.
|
// Get the base storage size.
|
||||||
m_base_storage_size = base_storages[2]->GetSize();
|
m_base_storage_size = base_storages[2]->GetSize();
|
||||||
{
|
{
|
||||||
auto size_guard = SCOPE_GUARD {
|
auto size_guard = SCOPE_GUARD({ m_base_storage_size = 0; });
|
||||||
m_base_storage_size = 0;
|
|
||||||
};
|
|
||||||
R_UNLESS(m_base_storage_size <= static_cast<s64>(HashSize)
|
R_UNLESS(m_base_storage_size <= static_cast<s64>(HashSize)
|
||||||
<< m_log_size_ratio << m_log_size_ratio,
|
<< m_log_size_ratio << m_log_size_ratio,
|
||||||
ResultHierarchicalSha256BaseStorageTooLarge);
|
ResultHierarchicalSha256BaseStorageTooLarge);
|
||||||
|
@ -98,9 +98,7 @@ Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) {
|
|||||||
|
|
||||||
Loader::ResultStatus ProgramMetadata::Reload(VirtualFile file) {
|
Loader::ResultStatus ProgramMetadata::Reload(VirtualFile file) {
|
||||||
const u64 original_program_id = aci_header.title_id;
|
const u64 original_program_id = aci_header.title_id;
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({ aci_header.title_id = original_program_id; });
|
||||||
aci_header.title_id = original_program_id;
|
|
||||||
};
|
|
||||||
|
|
||||||
return this->Load(file);
|
return this->Load(file);
|
||||||
}
|
}
|
||||||
|
@ -14,11 +14,48 @@ namespace FileSys {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
void PrintSaveDataAttributeWarnings(SaveDataAttribute meta) {
|
||||||
|
if (meta.type == SaveDataType::SystemSaveData || meta.type == SaveDataType::SaveData) {
|
||||||
|
if (meta.zero_1 != 0) {
|
||||||
|
LOG_WARNING(Service_FS,
|
||||||
|
"Possibly incorrect SaveDataAttribute, type is "
|
||||||
|
"SystemSaveData||SaveData but offset 0x28 is non-zero ({:016X}).",
|
||||||
|
meta.zero_1);
|
||||||
|
}
|
||||||
|
if (meta.zero_2 != 0) {
|
||||||
|
LOG_WARNING(Service_FS,
|
||||||
|
"Possibly incorrect SaveDataAttribute, type is "
|
||||||
|
"SystemSaveData||SaveData but offset 0x30 is non-zero ({:016X}).",
|
||||||
|
meta.zero_2);
|
||||||
|
}
|
||||||
|
if (meta.zero_3 != 0) {
|
||||||
|
LOG_WARNING(Service_FS,
|
||||||
|
"Possibly incorrect SaveDataAttribute, type is "
|
||||||
|
"SystemSaveData||SaveData but offset 0x38 is non-zero ({:016X}).",
|
||||||
|
meta.zero_3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (meta.type == SaveDataType::SystemSaveData && meta.title_id != 0) {
|
||||||
|
LOG_WARNING(Service_FS,
|
||||||
|
"Possibly incorrect SaveDataAttribute, type is SystemSaveData but title_id is "
|
||||||
|
"non-zero ({:016X}).",
|
||||||
|
meta.title_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (meta.type == SaveDataType::DeviceSaveData && meta.user_id != u128{0, 0}) {
|
||||||
|
LOG_WARNING(Service_FS,
|
||||||
|
"Possibly incorrect SaveDataAttribute, type is DeviceSaveData but user_id is "
|
||||||
|
"non-zero ({:016X}{:016X})",
|
||||||
|
meta.user_id[1], meta.user_id[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool ShouldSaveDataBeAutomaticallyCreated(SaveDataSpaceId space, const SaveDataAttribute& attr) {
|
bool ShouldSaveDataBeAutomaticallyCreated(SaveDataSpaceId space, const SaveDataAttribute& attr) {
|
||||||
return attr.type == SaveDataType::Cache || attr.type == SaveDataType::Temporary ||
|
return attr.type == SaveDataType::CacheStorage || attr.type == SaveDataType::TemporaryStorage ||
|
||||||
(space == SaveDataSpaceId::User && ///< Normal Save Data -- Current Title & User
|
(space == SaveDataSpaceId::NandUser && ///< Normal Save Data -- Current Title & User
|
||||||
(attr.type == SaveDataType::Account || attr.type == SaveDataType::Device) &&
|
(attr.type == SaveDataType::SaveData || attr.type == SaveDataType::DeviceSaveData) &&
|
||||||
attr.program_id == 0 && attr.system_save_data_id == 0);
|
attr.title_id == 0 && attr.save_id == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u64 title_id,
|
std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u64 title_id,
|
||||||
@ -26,7 +63,7 @@ std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u
|
|||||||
// Only detect nand user saves.
|
// Only detect nand user saves.
|
||||||
const auto space_id_path = [space_id]() -> std::string_view {
|
const auto space_id_path = [space_id]() -> std::string_view {
|
||||||
switch (space_id) {
|
switch (space_id) {
|
||||||
case SaveDataSpaceId::User:
|
case SaveDataSpaceId::NandUser:
|
||||||
return "/user/save";
|
return "/user/save";
|
||||||
default:
|
default:
|
||||||
return "";
|
return "";
|
||||||
@ -42,9 +79,9 @@ std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u
|
|||||||
|
|
||||||
// Only detect account/device saves from the future location.
|
// Only detect account/device saves from the future location.
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case SaveDataType::Account:
|
case SaveDataType::SaveData:
|
||||||
return fmt::format("{}/account/{}/{:016X}/0", space_id_path, uuid.RawString(), title_id);
|
return fmt::format("{}/account/{}/{:016X}/0", space_id_path, uuid.RawString(), title_id);
|
||||||
case SaveDataType::Device:
|
case SaveDataType::DeviceSaveData:
|
||||||
return fmt::format("{}/device/{:016X}/0", space_id_path, title_id);
|
return fmt::format("{}/device/{:016X}/0", space_id_path, title_id);
|
||||||
default:
|
default:
|
||||||
return "";
|
return "";
|
||||||
@ -53,6 +90,13 @@ std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u
|
|||||||
|
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
|
std::string SaveDataAttribute::DebugInfo() const {
|
||||||
|
return fmt::format("[title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}, type={:02X}, "
|
||||||
|
"rank={}, index={}]",
|
||||||
|
title_id, user_id[1], user_id[0], save_id, static_cast<u8>(type),
|
||||||
|
static_cast<u8>(rank), index);
|
||||||
|
}
|
||||||
|
|
||||||
SaveDataFactory::SaveDataFactory(Core::System& system_, ProgramId program_id_,
|
SaveDataFactory::SaveDataFactory(Core::System& system_, ProgramId program_id_,
|
||||||
VirtualDir save_directory_)
|
VirtualDir save_directory_)
|
||||||
: system{system_}, program_id{program_id_}, dir{std::move(save_directory_)} {
|
: system{system_}, program_id{program_id_}, dir{std::move(save_directory_)} {
|
||||||
@ -64,16 +108,18 @@ SaveDataFactory::SaveDataFactory(Core::System& system_, ProgramId program_id_,
|
|||||||
SaveDataFactory::~SaveDataFactory() = default;
|
SaveDataFactory::~SaveDataFactory() = default;
|
||||||
|
|
||||||
VirtualDir SaveDataFactory::Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
|
VirtualDir SaveDataFactory::Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
|
||||||
const auto save_directory = GetFullPath(program_id, dir, space, meta.type, meta.program_id,
|
PrintSaveDataAttributeWarnings(meta);
|
||||||
meta.user_id, meta.system_save_data_id);
|
|
||||||
|
const auto save_directory =
|
||||||
|
GetFullPath(program_id, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id);
|
||||||
|
|
||||||
return dir->CreateDirectoryRelative(save_directory);
|
return dir->CreateDirectoryRelative(save_directory);
|
||||||
}
|
}
|
||||||
|
|
||||||
VirtualDir SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
|
VirtualDir SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
|
||||||
|
|
||||||
const auto save_directory = GetFullPath(program_id, dir, space, meta.type, meta.program_id,
|
const auto save_directory =
|
||||||
meta.user_id, meta.system_save_data_id);
|
GetFullPath(program_id, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id);
|
||||||
|
|
||||||
auto out = dir->GetDirectoryRelative(save_directory);
|
auto out = dir->GetDirectoryRelative(save_directory);
|
||||||
|
|
||||||
@ -90,11 +136,11 @@ VirtualDir SaveDataFactory::GetSaveDataSpaceDirectory(SaveDataSpaceId space) con
|
|||||||
|
|
||||||
std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) {
|
std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) {
|
||||||
switch (space) {
|
switch (space) {
|
||||||
case SaveDataSpaceId::System:
|
case SaveDataSpaceId::NandSystem:
|
||||||
return "/system/";
|
return "/system/";
|
||||||
case SaveDataSpaceId::User:
|
case SaveDataSpaceId::NandUser:
|
||||||
return "/user/";
|
return "/user/";
|
||||||
case SaveDataSpaceId::Temporary:
|
case SaveDataSpaceId::TemporaryStorage:
|
||||||
return "/temp/";
|
return "/temp/";
|
||||||
default:
|
default:
|
||||||
ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space));
|
ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space));
|
||||||
@ -107,7 +153,7 @@ std::string SaveDataFactory::GetFullPath(ProgramId program_id, VirtualDir dir,
|
|||||||
u128 user_id, u64 save_id) {
|
u128 user_id, u64 save_id) {
|
||||||
// According to switchbrew, if a save is of type SaveData and the title id field is 0, it should
|
// According to switchbrew, if a save is of type SaveData and the title id field is 0, it should
|
||||||
// be interpreted as the title id of the current process.
|
// be interpreted as the title id of the current process.
|
||||||
if (type == SaveDataType::Account || type == SaveDataType::Device) {
|
if (type == SaveDataType::SaveData || type == SaveDataType::DeviceSaveData) {
|
||||||
if (title_id == 0) {
|
if (title_id == 0) {
|
||||||
title_id = program_id;
|
title_id = program_id;
|
||||||
}
|
}
|
||||||
@ -127,16 +173,16 @@ std::string SaveDataFactory::GetFullPath(ProgramId program_id, VirtualDir dir,
|
|||||||
std::string out = GetSaveDataSpaceIdPath(space);
|
std::string out = GetSaveDataSpaceIdPath(space);
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case SaveDataType::System:
|
case SaveDataType::SystemSaveData:
|
||||||
return fmt::format("{}save/{:016X}/{:016X}{:016X}", out, save_id, user_id[1], user_id[0]);
|
return fmt::format("{}save/{:016X}/{:016X}{:016X}", out, save_id, user_id[1], user_id[0]);
|
||||||
case SaveDataType::Account:
|
case SaveDataType::SaveData:
|
||||||
case SaveDataType::Device:
|
case SaveDataType::DeviceSaveData:
|
||||||
return fmt::format("{}save/{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
|
return fmt::format("{}save/{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
|
||||||
title_id);
|
title_id);
|
||||||
case SaveDataType::Temporary:
|
case SaveDataType::TemporaryStorage:
|
||||||
return fmt::format("{}{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
|
return fmt::format("{}{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
|
||||||
title_id);
|
title_id);
|
||||||
case SaveDataType::Cache:
|
case SaveDataType::CacheStorage:
|
||||||
return fmt::format("{}save/cache/{:016X}", out, title_id);
|
return fmt::format("{}save/cache/{:016X}", out, title_id);
|
||||||
default:
|
default:
|
||||||
ASSERT_MSG(false, "Unrecognized SaveDataType: {:02X}", static_cast<u8>(type));
|
ASSERT_MSG(false, "Unrecognized SaveDataType: {:02X}", static_cast<u8>(type));
|
||||||
@ -156,7 +202,7 @@ std::string SaveDataFactory::GetUserGameSaveDataRoot(u128 user_id, bool future)
|
|||||||
SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
|
SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
|
||||||
u128 user_id) const {
|
u128 user_id) const {
|
||||||
const auto path =
|
const auto path =
|
||||||
GetFullPath(program_id, dir, SaveDataSpaceId::User, type, title_id, user_id, 0);
|
GetFullPath(program_id, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
|
||||||
const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
|
const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
|
||||||
|
|
||||||
const auto size_file = relative_dir->GetFile(GetSaveDataSizeFileName());
|
const auto size_file = relative_dir->GetFile(GetSaveDataSizeFileName());
|
||||||
@ -175,7 +221,7 @@ SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
|
|||||||
void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
|
void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
|
||||||
SaveDataSize new_value) const {
|
SaveDataSize new_value) const {
|
||||||
const auto path =
|
const auto path =
|
||||||
GetFullPath(program_id, dir, SaveDataSpaceId::User, type, title_id, user_id, 0);
|
GetFullPath(program_id, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
|
||||||
const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
|
const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
|
||||||
|
|
||||||
const auto size_file = relative_dir->CreateFile(GetSaveDataSizeFileName());
|
const auto size_file = relative_dir->CreateFile(GetSaveDataSizeFileName());
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/file_sys/fs_save_data_types.h"
|
|
||||||
#include "core/file_sys/vfs/vfs.h"
|
#include "core/file_sys/vfs/vfs.h"
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
@ -17,6 +16,73 @@ class System;
|
|||||||
|
|
||||||
namespace FileSys {
|
namespace FileSys {
|
||||||
|
|
||||||
|
enum class SaveDataSpaceId : u8 {
|
||||||
|
NandSystem = 0,
|
||||||
|
NandUser = 1,
|
||||||
|
SdCardSystem = 2,
|
||||||
|
TemporaryStorage = 3,
|
||||||
|
SdCardUser = 4,
|
||||||
|
ProperSystem = 100,
|
||||||
|
SafeMode = 101,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SaveDataType : u8 {
|
||||||
|
SystemSaveData = 0,
|
||||||
|
SaveData = 1,
|
||||||
|
BcatDeliveryCacheStorage = 2,
|
||||||
|
DeviceSaveData = 3,
|
||||||
|
TemporaryStorage = 4,
|
||||||
|
CacheStorage = 5,
|
||||||
|
SystemBcat = 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SaveDataRank : u8 {
|
||||||
|
Primary = 0,
|
||||||
|
Secondary = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SaveDataFlags : u32 {
|
||||||
|
None = (0 << 0),
|
||||||
|
KeepAfterResettingSystemSaveData = (1 << 0),
|
||||||
|
KeepAfterRefurbishment = (1 << 1),
|
||||||
|
KeepAfterResettingSystemSaveDataWithoutUserSaveData = (1 << 2),
|
||||||
|
NeedsSecureDelete = (1 << 3),
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SaveDataAttribute {
|
||||||
|
u64 title_id;
|
||||||
|
u128 user_id;
|
||||||
|
u64 save_id;
|
||||||
|
SaveDataType type;
|
||||||
|
SaveDataRank rank;
|
||||||
|
u16 index;
|
||||||
|
INSERT_PADDING_BYTES_NOINIT(4);
|
||||||
|
u64 zero_1;
|
||||||
|
u64 zero_2;
|
||||||
|
u64 zero_3;
|
||||||
|
|
||||||
|
std::string DebugInfo() const;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(SaveDataAttribute) == 0x40, "SaveDataAttribute has incorrect size.");
|
||||||
|
|
||||||
|
struct SaveDataExtraData {
|
||||||
|
SaveDataAttribute attr;
|
||||||
|
u64 owner_id;
|
||||||
|
s64 timestamp;
|
||||||
|
SaveDataFlags flags;
|
||||||
|
INSERT_PADDING_BYTES_NOINIT(4);
|
||||||
|
s64 available_size;
|
||||||
|
s64 journal_size;
|
||||||
|
s64 commit_id;
|
||||||
|
std::array<u8, 0x190> unused;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(SaveDataExtraData) == 0x200, "SaveDataExtraData has incorrect size.");
|
||||||
|
|
||||||
|
struct SaveDataSize {
|
||||||
|
u64 normal;
|
||||||
|
u64 journal;
|
||||||
|
};
|
||||||
|
|
||||||
constexpr const char* GetSaveDataSizeFileName() {
|
constexpr const char* GetSaveDataSizeFileName() {
|
||||||
return ".yuzu_save_size";
|
return ".yuzu_save_size";
|
||||||
}
|
}
|
||||||
|
@ -24,9 +24,7 @@ Result KClientSession::SendSyncRequest(uintptr_t address, size_t size) {
|
|||||||
// Create a session request.
|
// Create a session request.
|
||||||
KSessionRequest* request = KSessionRequest::Create(m_kernel);
|
KSessionRequest* request = KSessionRequest::Create(m_kernel);
|
||||||
R_UNLESS(request != nullptr, ResultOutOfResource);
|
R_UNLESS(request != nullptr, ResultOutOfResource);
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({ request->Close(); });
|
||||||
request->Close();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Initialize the request.
|
// Initialize the request.
|
||||||
request->Initialize(nullptr, address, size);
|
request->Initialize(nullptr, address, size);
|
||||||
@ -39,9 +37,7 @@ Result KClientSession::SendAsyncRequest(KEvent* event, uintptr_t address, size_t
|
|||||||
// Create a session request.
|
// Create a session request.
|
||||||
KSessionRequest* request = KSessionRequest::Create(m_kernel);
|
KSessionRequest* request = KSessionRequest::Create(m_kernel);
|
||||||
R_UNLESS(request != nullptr, ResultOutOfResource);
|
R_UNLESS(request != nullptr, ResultOutOfResource);
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({ request->Close(); });
|
||||||
request->Close();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Initialize the request.
|
// Initialize the request.
|
||||||
request->Initialize(event, address, size);
|
request->Initialize(event, address, size);
|
||||||
|
@ -1305,11 +1305,11 @@ Result KPageTableBase::UnmapCodeMemory(KProcessAddress dst_address, KProcessAddr
|
|||||||
|
|
||||||
// Ensure that we maintain the instruction cache.
|
// Ensure that we maintain the instruction cache.
|
||||||
bool reprotected_pages = false;
|
bool reprotected_pages = false;
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({
|
||||||
if (reprotected_pages && any_code_pages) {
|
if (reprotected_pages && any_code_pages) {
|
||||||
InvalidateInstructionCache(m_kernel, this, dst_address, size);
|
InvalidateInstructionCache(m_kernel, this, dst_address, size);
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
// Unmap.
|
// Unmap.
|
||||||
{
|
{
|
||||||
@ -1397,9 +1397,7 @@ Result KPageTableBase::MapInsecureMemory(KProcessAddress address, size_t size) {
|
|||||||
// Close the opened pages when we're done with them.
|
// 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
|
// If the mapping succeeds, each page will gain an extra reference, otherwise they will be freed
|
||||||
// automatically.
|
// automatically.
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({ pg.Close(); });
|
||||||
pg.Close();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Clear all the newly allocated pages.
|
// Clear all the newly allocated pages.
|
||||||
for (const auto& it : pg) {
|
for (const auto& it : pg) {
|
||||||
@ -1605,9 +1603,7 @@ Result KPageTableBase::AllocateAndMapPagesImpl(PageLinkedList* page_list, KProce
|
|||||||
m_kernel.MemoryManager().AllocateAndOpen(std::addressof(pg), num_pages, m_allocate_option));
|
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.
|
// Ensure that the page group is closed when we're done working with it.
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({ pg.Close(); });
|
||||||
pg.Close();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Clear all pages.
|
// Clear all pages.
|
||||||
for (const auto& it : pg) {
|
for (const auto& it : pg) {
|
||||||
@ -2195,9 +2191,7 @@ Result KPageTableBase::SetHeapSize(KProcessAddress* out, size_t size) {
|
|||||||
// Close the opened pages when we're done with them.
|
// 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
|
// If the mapping succeeds, each page will gain an extra reference, otherwise they will be freed
|
||||||
// automatically.
|
// automatically.
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({ pg.Close(); });
|
||||||
pg.Close();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Clear all the newly allocated pages.
|
// Clear all the newly allocated pages.
|
||||||
for (const auto& it : pg) {
|
for (const auto& it : pg) {
|
||||||
@ -2598,9 +2592,7 @@ Result KPageTableBase::UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddre
|
|||||||
// Temporarily unlock ourselves, so that other operations can occur while we flush the
|
// Temporarily unlock ourselves, so that other operations can occur while we flush the
|
||||||
// region.
|
// region.
|
||||||
m_general_lock.Unlock();
|
m_general_lock.Unlock();
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({ m_general_lock.Lock(); });
|
||||||
m_general_lock.Lock();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Flush the region.
|
// Flush the region.
|
||||||
R_ASSERT(FlushDataCache(dst_address, size));
|
R_ASSERT(FlushDataCache(dst_address, size));
|
||||||
@ -3319,10 +3311,10 @@ Result KPageTableBase::ReadIoMemoryImpl(KProcessAddress dst_addr, KPhysicalAddre
|
|||||||
// Ensure we unmap the io memory when we're done with it.
|
// Ensure we unmap the io memory when we're done with it.
|
||||||
const KPageProperties unmap_properties =
|
const KPageProperties unmap_properties =
|
||||||
KPageProperties{KMemoryPermission::None, false, false, DisableMergeAttribute::None};
|
KPageProperties{KMemoryPermission::None, false, false, DisableMergeAttribute::None};
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({
|
||||||
R_ASSERT(this->Operate(updater.GetPageList(), io_addr, map_size / PageSize, 0, false,
|
R_ASSERT(this->Operate(updater.GetPageList(), io_addr, map_size / PageSize, 0, false,
|
||||||
unmap_properties, OperationType::Unmap, true));
|
unmap_properties, OperationType::Unmap, true));
|
||||||
};
|
});
|
||||||
|
|
||||||
// Read the memory.
|
// Read the memory.
|
||||||
const KProcessAddress read_addr = io_addr + (GetInteger(phys_addr) & (PageSize - 1));
|
const KProcessAddress read_addr = io_addr + (GetInteger(phys_addr) & (PageSize - 1));
|
||||||
@ -3355,10 +3347,10 @@ Result KPageTableBase::WriteIoMemoryImpl(KPhysicalAddress phys_addr, KProcessAdd
|
|||||||
// Ensure we unmap the io memory when we're done with it.
|
// Ensure we unmap the io memory when we're done with it.
|
||||||
const KPageProperties unmap_properties =
|
const KPageProperties unmap_properties =
|
||||||
KPageProperties{KMemoryPermission::None, false, false, DisableMergeAttribute::None};
|
KPageProperties{KMemoryPermission::None, false, false, DisableMergeAttribute::None};
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({
|
||||||
R_ASSERT(this->Operate(updater.GetPageList(), io_addr, map_size / PageSize, 0, false,
|
R_ASSERT(this->Operate(updater.GetPageList(), io_addr, map_size / PageSize, 0, false,
|
||||||
unmap_properties, OperationType::Unmap, true));
|
unmap_properties, OperationType::Unmap, true));
|
||||||
};
|
});
|
||||||
|
|
||||||
// Write the memory.
|
// Write the memory.
|
||||||
const KProcessAddress write_addr = io_addr + (GetInteger(phys_addr) & (PageSize - 1));
|
const KProcessAddress write_addr = io_addr + (GetInteger(phys_addr) & (PageSize - 1));
|
||||||
@ -4499,14 +4491,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
|
// If the partial pages are mapped, an extra reference will have been opened. Otherwise, they'll
|
||||||
// free on scope exit.
|
// free on scope exit.
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({
|
||||||
if (start_partial_page != 0) {
|
if (start_partial_page != 0) {
|
||||||
m_kernel.MemoryManager().Close(start_partial_page, 1);
|
m_kernel.MemoryManager().Close(start_partial_page, 1);
|
||||||
}
|
}
|
||||||
if (end_partial_page != 0) {
|
if (end_partial_page != 0) {
|
||||||
m_kernel.MemoryManager().Close(end_partial_page, 1);
|
m_kernel.MemoryManager().Close(end_partial_page, 1);
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
ON_RESULT_FAILURE {
|
ON_RESULT_FAILURE {
|
||||||
if (cur_mapped_addr != dst_addr) {
|
if (cur_mapped_addr != dst_addr) {
|
||||||
@ -5174,10 +5166,10 @@ Result KPageTableBase::MapPhysicalMemory(KProcessAddress address, size_t size) {
|
|||||||
GetCurrentProcess(m_kernel).GetId(), m_heap_fill_value));
|
GetCurrentProcess(m_kernel).GetId(), m_heap_fill_value));
|
||||||
|
|
||||||
// If we fail in the next bit (or retry), we need to cleanup the pages.
|
// 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.OpenFirst();
|
||||||
pg.Close();
|
pg.Close();
|
||||||
};
|
});
|
||||||
|
|
||||||
// Map the memory.
|
// Map the memory.
|
||||||
{
|
{
|
||||||
@ -5702,9 +5694,7 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
|
|||||||
|
|
||||||
// Ensure that any pages we track are closed on exit.
|
// Ensure that any pages we track are closed on exit.
|
||||||
KPageGroup pages_to_close(m_kernel, this->GetBlockInfoManager());
|
KPageGroup pages_to_close(m_kernel, this->GetBlockInfoManager());
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({ pages_to_close.CloseAndReset(); });
|
||||||
pages_to_close.CloseAndReset();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Make a page group representing the region to unmap.
|
// Make a page group representing the region to unmap.
|
||||||
this->MakePageGroup(pages_to_close, virt_addr, num_pages);
|
this->MakePageGroup(pages_to_close, virt_addr, num_pages);
|
||||||
|
@ -77,9 +77,7 @@ Result TerminateChildren(KernelCore& kernel, KProcess* process,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Terminate and close the thread.
|
// Terminate and close the thread.
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({ cur_child->Close(); });
|
||||||
cur_child->Close();
|
|
||||||
};
|
|
||||||
|
|
||||||
if (const Result terminate_result = cur_child->Terminate();
|
if (const Result terminate_result = cur_child->Terminate();
|
||||||
ResultTerminationRequested == terminate_result) {
|
ResultTerminationRequested == terminate_result) {
|
||||||
@ -468,11 +466,11 @@ void KProcess::DoWorkerTaskImpl() {
|
|||||||
|
|
||||||
Result KProcess::StartTermination() {
|
Result KProcess::StartTermination() {
|
||||||
// Finalize the handle table when we're done, if the process isn't immortal.
|
// Finalize the handle table when we're done, if the process isn't immortal.
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({
|
||||||
if (!m_is_immortal) {
|
if (!m_is_immortal) {
|
||||||
this->FinalizeHandleTable();
|
this->FinalizeHandleTable();
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
// Terminate child threads other than the current one.
|
// Terminate child threads other than the current one.
|
||||||
R_RETURN(TerminateChildren(m_kernel, this, GetCurrentThreadPointer(m_kernel)));
|
R_RETURN(TerminateChildren(m_kernel, this, GetCurrentThreadPointer(m_kernel)));
|
||||||
@ -966,9 +964,7 @@ Result KProcess::Run(s32 priority, size_t stack_size) {
|
|||||||
// Create a new thread for the process.
|
// Create a new thread for the process.
|
||||||
KThread* main_thread = KThread::Create(m_kernel);
|
KThread* main_thread = KThread::Create(m_kernel);
|
||||||
R_UNLESS(main_thread != nullptr, ResultOutOfResource);
|
R_UNLESS(main_thread != nullptr, ResultOutOfResource);
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({ main_thread->Close(); });
|
||||||
main_thread->Close();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Initialize the thread.
|
// Initialize the thread.
|
||||||
R_TRY(KThread::InitializeUserThread(m_kernel.System(), main_thread, this->GetEntryPoint(), 0,
|
R_TRY(KThread::InitializeUserThread(m_kernel.System(), main_thread, this->GetEntryPoint(), 0,
|
||||||
@ -1159,9 +1155,7 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
|
|||||||
Kernel::CreateResourceLimitForProcess(m_kernel.System(), physical_memory_size);
|
Kernel::CreateResourceLimitForProcess(m_kernel.System(), physical_memory_size);
|
||||||
|
|
||||||
// Ensure we maintain a clean state on exit.
|
// Ensure we maintain a clean state on exit.
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({ res_limit->Close(); });
|
||||||
res_limit->Close();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Declare flags and code address.
|
// Declare flags and code address.
|
||||||
Svc::CreateProcessFlag flag{};
|
Svc::CreateProcessFlag flag{};
|
||||||
|
@ -651,11 +651,11 @@ Result ReceiveMessage(KernelCore& kernel, bool& recv_list_broken, uint64_t dst_m
|
|||||||
// Process any special data.
|
// Process any special data.
|
||||||
if (src_header.GetHasSpecialHeader()) {
|
if (src_header.GetHasSpecialHeader()) {
|
||||||
// After we process, make sure we track whether the receive list is broken.
|
// After we process, make sure we track whether the receive list is broken.
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({
|
||||||
if (offset > dst_recv_list_idx) {
|
if (offset > dst_recv_list_idx) {
|
||||||
recv_list_broken = true;
|
recv_list_broken = true;
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
// Process special data.
|
// Process special data.
|
||||||
R_TRY(ProcessMessageSpecialData<false>(offset, dst_process, src_process, src_thread,
|
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.
|
// Process any pointer buffers.
|
||||||
for (auto i = 0; i < src_header.GetPointerCount(); ++i) {
|
for (auto i = 0; i < src_header.GetPointerCount(); ++i) {
|
||||||
// After we process, make sure we track whether the receive list is broken.
|
// After we process, make sure we track whether the receive list is broken.
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({
|
||||||
if (offset > dst_recv_list_idx) {
|
if (offset > dst_recv_list_idx) {
|
||||||
recv_list_broken = true;
|
recv_list_broken = true;
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
R_TRY(ProcessReceiveMessagePointerDescriptors(
|
R_TRY(ProcessReceiveMessagePointerDescriptors(
|
||||||
offset, pointer_key, dst_page_table, src_page_table, dst_msg, src_msg, dst_recv_list,
|
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.
|
// Process any map alias buffers.
|
||||||
for (auto i = 0; i < src_header.GetMapAliasCount(); ++i) {
|
for (auto i = 0; i < src_header.GetMapAliasCount(); ++i) {
|
||||||
// After we process, make sure we track whether the receive list is broken.
|
// After we process, make sure we track whether the receive list is broken.
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({
|
||||||
if (offset > dst_recv_list_idx) {
|
if (offset > dst_recv_list_idx) {
|
||||||
recv_list_broken = true;
|
recv_list_broken = true;
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
// We process in order send, recv, exch. Buffers after send (recv/exch) are ReadWrite.
|
// We process in order send, recv, exch. Buffers after send (recv/exch) are ReadWrite.
|
||||||
const KMemoryPermission perm = (i >= src_header.GetSendCount())
|
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.
|
// Process any raw data.
|
||||||
if (const auto raw_count = src_header.GetRawCount(); raw_count != 0) {
|
if (const auto raw_count = src_header.GetRawCount(); raw_count != 0) {
|
||||||
// After we process, make sure we track whether the receive list is broken.
|
// 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) {
|
if (offset + raw_count > dst_recv_list_idx) {
|
||||||
recv_list_broken = true;
|
recv_list_broken = true;
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
// Get the offset and size.
|
// Get the offset and size.
|
||||||
const size_t offset_words = offset * sizeof(u32);
|
const size_t offset_words = offset * sizeof(u32);
|
||||||
@ -1124,9 +1124,7 @@ Result KServerSession::ReceiveRequest(uintptr_t server_message, uintptr_t server
|
|||||||
client_thread->Open();
|
client_thread->Open();
|
||||||
}
|
}
|
||||||
|
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({ client_thread->Close(); });
|
||||||
client_thread->Close();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Set the request as our current.
|
// Set the request as our current.
|
||||||
m_current_request = request;
|
m_current_request = request;
|
||||||
@ -1176,9 +1174,7 @@ Result KServerSession::ReceiveRequest(uintptr_t server_message, uintptr_t server
|
|||||||
// Reply to the client.
|
// Reply to the client.
|
||||||
{
|
{
|
||||||
// After we reply, close our reference to the request.
|
// After we reply, close our reference to the request.
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({ request->Close(); });
|
||||||
request->Close();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get the event to check whether the request is async.
|
// Get the event to check whether the request is async.
|
||||||
if (KEvent* event = request->GetEvent(); event != nullptr) {
|
if (KEvent* event = request->GetEvent(); event != nullptr) {
|
||||||
@ -1240,9 +1236,7 @@ Result KServerSession::SendReply(uintptr_t server_message, uintptr_t server_buff
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Close reference to the request once we're done processing it.
|
// Close reference to the request once we're done processing it.
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({ request->Close(); });
|
||||||
request->Close();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Extract relevant information from the request.
|
// Extract relevant information from the request.
|
||||||
const uint64_t client_message = request->GetAddress();
|
const uint64_t client_message = request->GetAddress();
|
||||||
@ -1400,9 +1394,7 @@ void KServerSession::CleanupRequests() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Close a reference to the request once it's cleaned up.
|
// Close a reference to the request once it's cleaned up.
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({ request->Close(); });
|
||||||
request->Close();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Extract relevant information from the request.
|
// Extract relevant information from the request.
|
||||||
const uint64_t client_message = request->GetAddress();
|
const uint64_t client_message = request->GetAddress();
|
||||||
@ -1499,9 +1491,7 @@ void KServerSession::OnClientClosed() {
|
|||||||
ASSERT(thread != nullptr);
|
ASSERT(thread != nullptr);
|
||||||
|
|
||||||
// Ensure that we close the request when done.
|
// Ensure that we close the request when done.
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({ request->Close(); });
|
||||||
request->Close();
|
|
||||||
};
|
|
||||||
|
|
||||||
// If we're terminating, close a reference to the thread and event.
|
// If we're terminating, close a reference to the thread and event.
|
||||||
if (terminate) {
|
if (terminate) {
|
||||||
|
@ -21,9 +21,7 @@ Result KThreadLocalPage::Initialize(KernelCore& kernel, KProcess* process) {
|
|||||||
// Allocate a new page.
|
// Allocate a new page.
|
||||||
KPageBuffer* page_buf = KPageBuffer::Allocate(kernel);
|
KPageBuffer* page_buf = KPageBuffer::Allocate(kernel);
|
||||||
R_UNLESS(page_buf != nullptr, ResultOutOfMemory);
|
R_UNLESS(page_buf != nullptr, ResultOutOfMemory);
|
||||||
auto page_buf_guard = SCOPE_GUARD {
|
auto page_buf_guard = SCOPE_GUARD({ KPageBuffer::Free(kernel, page_buf); });
|
||||||
KPageBuffer::Free(kernel, page_buf);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Map the address in.
|
// Map the address in.
|
||||||
const auto phys_addr = kernel.System().DeviceMemory().GetPhysicalAddr(page_buf);
|
const auto phys_addr = kernel.System().DeviceMemory().GetPhysicalAddr(page_buf);
|
||||||
|
@ -24,9 +24,7 @@ Result KTransferMemory::Initialize(KProcessAddress addr, std::size_t size,
|
|||||||
|
|
||||||
// Construct the page group, guarding to make sure our state is valid on exit.
|
// Construct the page group, guarding to make sure our state is valid on exit.
|
||||||
m_page_group.emplace(m_kernel, page_table.GetBlockInfoManager());
|
m_page_group.emplace(m_kernel, page_table.GetBlockInfoManager());
|
||||||
auto pg_guard = SCOPE_GUARD {
|
auto pg_guard = SCOPE_GUARD({ m_page_group.reset(); });
|
||||||
m_page_group.reset();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Lock the memory.
|
// Lock the memory.
|
||||||
R_TRY(page_table.LockForTransferMemory(std::addressof(*m_page_group), addr, size,
|
R_TRY(page_table.LockForTransferMemory(std::addressof(*m_page_group), addr, size,
|
||||||
|
@ -109,9 +109,7 @@ struct KernelCore::Impl {
|
|||||||
|
|
||||||
void Shutdown() {
|
void Shutdown() {
|
||||||
is_shutting_down.store(true, std::memory_order_relaxed);
|
is_shutting_down.store(true, std::memory_order_relaxed);
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({ is_shutting_down.store(false, std::memory_order_relaxed); });
|
||||||
is_shutting_down.store(false, std::memory_order_relaxed);
|
|
||||||
};
|
|
||||||
|
|
||||||
CloseServices();
|
CloseServices();
|
||||||
|
|
||||||
@ -1082,9 +1080,7 @@ std::jthread KernelCore::RunOnHostCoreProcess(std::string&& process_name,
|
|||||||
process->Initialize(Svc::CreateProcessParameter{}, GetSystemResourceLimit(), false)));
|
process->Initialize(Svc::CreateProcessParameter{}, GetSystemResourceLimit(), false)));
|
||||||
|
|
||||||
// Ensure that we don't hold onto any extra references.
|
// Ensure that we don't hold onto any extra references.
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({ process->Close(); });
|
||||||
process->Close();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Register the new process.
|
// Register the new process.
|
||||||
KProcess::Register(*this, process);
|
KProcess::Register(*this, process);
|
||||||
@ -1112,9 +1108,7 @@ void KernelCore::RunOnGuestCoreProcess(std::string&& process_name, std::function
|
|||||||
process->Initialize(Svc::CreateProcessParameter{}, GetSystemResourceLimit(), false)));
|
process->Initialize(Svc::CreateProcessParameter{}, GetSystemResourceLimit(), false)));
|
||||||
|
|
||||||
// Ensure that we don't hold onto any extra references.
|
// Ensure that we don't hold onto any extra references.
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({ process->Close(); });
|
||||||
process->Close();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Register the new process.
|
// Register the new process.
|
||||||
KProcess::Register(*this, process);
|
KProcess::Register(*this, process);
|
||||||
|
@ -45,9 +45,7 @@ Result CreateCodeMemory(Core::System& system, Handle* out, u64 address, uint64_t
|
|||||||
|
|
||||||
KCodeMemory* code_mem = KCodeMemory::Create(kernel);
|
KCodeMemory* code_mem = KCodeMemory::Create(kernel);
|
||||||
R_UNLESS(code_mem != nullptr, ResultOutOfResource);
|
R_UNLESS(code_mem != nullptr, ResultOutOfResource);
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({ code_mem->Close(); });
|
||||||
code_mem->Close();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Verify that the region is in range.
|
// Verify that the region is in range.
|
||||||
R_UNLESS(GetCurrentProcess(system.Kernel()).GetPageTable().Contains(address, size),
|
R_UNLESS(GetCurrentProcess(system.Kernel()).GetPageTable().Contains(address, size),
|
||||||
|
@ -28,9 +28,7 @@ Result CreateDeviceAddressSpace(Core::System& system, Handle* out, uint64_t das_
|
|||||||
// Create the device address space.
|
// Create the device address space.
|
||||||
KDeviceAddressSpace* das = KDeviceAddressSpace::Create(system.Kernel());
|
KDeviceAddressSpace* das = KDeviceAddressSpace::Create(system.Kernel());
|
||||||
R_UNLESS(das != nullptr, ResultOutOfResource);
|
R_UNLESS(das != nullptr, ResultOutOfResource);
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({ das->Close(); });
|
||||||
das->Close();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Initialize the device address space.
|
// Initialize the device address space.
|
||||||
R_TRY(das->Initialize(das_address, das_size));
|
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();
|
event_reservation.Commit();
|
||||||
|
|
||||||
// Ensure that we clean up the event (and its only references are handle table) on function end.
|
// 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->GetReadableEvent().Close();
|
||||||
event->Close();
|
event->Close();
|
||||||
};
|
});
|
||||||
|
|
||||||
// Register the event.
|
// Register the event.
|
||||||
KEvent::Register(kernel, 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.
|
// Ensure handles are closed when we're done.
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({
|
||||||
for (auto i = 0; i < num_handles; ++i) {
|
for (auto i = 0; i < num_handles; ++i) {
|
||||||
objs[i]->Close();
|
objs[i]->Close();
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
R_RETURN(ReplyAndReceiveImpl(kernel, out_index, message, buffer_size, message_paddr, objs,
|
R_RETURN(ReplyAndReceiveImpl(kernel, out_index, message, buffer_size, message_paddr, objs,
|
||||||
num_handles, reply_target, timeout_ns));
|
num_handles, reply_target, timeout_ns));
|
||||||
@ -208,10 +208,10 @@ Result SendAsyncRequestWithUserBuffer(Core::System& system, Handle* out_event_ha
|
|||||||
event_reservation.Commit();
|
event_reservation.Commit();
|
||||||
|
|
||||||
// At end of scope, kill the standing references to the sub events.
|
// At end of scope, kill the standing references to the sub events.
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({
|
||||||
event->GetReadableEvent().Close();
|
event->GetReadableEvent().Close();
|
||||||
event->Close();
|
event->Close();
|
||||||
};
|
});
|
||||||
|
|
||||||
// Register the event.
|
// Register the event.
|
||||||
KEvent::Register(system.Kernel(), 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);
|
port->Initialize(max_sessions, is_light, name);
|
||||||
|
|
||||||
// Ensure that we clean up the port (and its only references are handle table) on function end.
|
// 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->GetServerPort().Close();
|
||||||
port->GetClientPort().Close();
|
port->GetClientPort().Close();
|
||||||
};
|
});
|
||||||
|
|
||||||
// Register the port.
|
// Register the port.
|
||||||
KPort::Register(kernel, 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);
|
KPort::Register(system.Kernel(), port);
|
||||||
|
|
||||||
// Ensure that our only reference to the port is in the handle table when we're done.
|
// 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->GetClientPort().Close();
|
||||||
port->GetServerPort().Close();
|
port->GetServerPort().Close();
|
||||||
};
|
});
|
||||||
|
|
||||||
// Register the handle in the table.
|
// Register the handle in the table.
|
||||||
R_TRY(handle_table.Add(out_server_handle, std::addressof(port->GetServerPort())));
|
R_TRY(handle_table.Add(out_server_handle, std::addressof(port->GetServerPort())));
|
||||||
|
@ -18,9 +18,7 @@ Result CreateResourceLimit(Core::System& system, Handle* out_handle) {
|
|||||||
R_UNLESS(resource_limit != nullptr, ResultOutOfResource);
|
R_UNLESS(resource_limit != nullptr, ResultOutOfResource);
|
||||||
|
|
||||||
// Ensure we don't leak a reference to the limit.
|
// Ensure we don't leak a reference to the limit.
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({ resource_limit->Close(); });
|
||||||
resource_limit->Close();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Initialize the resource limit.
|
// Initialize the resource limit.
|
||||||
resource_limit->Initialize();
|
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
|
// Ensure that we clean up the session (and its only references are handle table) on function
|
||||||
// end.
|
// end.
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({
|
||||||
session->GetClientSession().Close();
|
session->GetClientSession().Close();
|
||||||
session->GetServerSession().Close();
|
session->GetServerSession().Close();
|
||||||
};
|
});
|
||||||
|
|
||||||
// Register the session.
|
// Register the session.
|
||||||
T::Register(system.Kernel(), 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.
|
// Ensure handles are closed when we're done.
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({
|
||||||
for (auto i = 0; i < num_handles; ++i) {
|
for (auto i = 0; i < num_handles; ++i) {
|
||||||
objs[i]->Close();
|
objs[i]->Close();
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
// Convert the timeout from nanoseconds to ticks.
|
// Convert the timeout from nanoseconds to ticks.
|
||||||
s64 timeout;
|
s64 timeout;
|
||||||
|
@ -51,9 +51,7 @@ Result CreateThread(Core::System& system, Handle* out_handle, u64 entry_point, u
|
|||||||
// Create the thread.
|
// Create the thread.
|
||||||
KThread* thread = KThread::Create(kernel);
|
KThread* thread = KThread::Create(kernel);
|
||||||
R_UNLESS(thread != nullptr, ResultOutOfResource)
|
R_UNLESS(thread != nullptr, ResultOutOfResource)
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({ thread->Close(); });
|
||||||
thread->Close();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Initialize the thread.
|
// Initialize the thread.
|
||||||
{
|
{
|
||||||
|
@ -52,9 +52,7 @@ Result CreateTransferMemory(Core::System& system, Handle* out, u64 address, u64
|
|||||||
R_UNLESS(trmem != nullptr, ResultOutOfResource);
|
R_UNLESS(trmem != nullptr, ResultOutOfResource);
|
||||||
|
|
||||||
// Ensure the only reference is in the handle table when we're done.
|
// Ensure the only reference is in the handle table when we're done.
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({ trmem->Close(); });
|
||||||
trmem->Close();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Ensure that the region is in range.
|
// Ensure that the region is in range.
|
||||||
R_UNLESS(process.GetPageTable().Contains(address, size), ResultInvalidCurrentMemory);
|
R_UNLESS(process.GetPageTable().Contains(address, size), ResultInvalidCurrentMemory);
|
||||||
|
@ -24,11 +24,11 @@ void AppletStorageChannel::Push(std::shared_ptr<IStorage> storage) {
|
|||||||
Result AppletStorageChannel::Pop(std::shared_ptr<IStorage>* out_storage) {
|
Result AppletStorageChannel::Pop(std::shared_ptr<IStorage>* out_storage) {
|
||||||
std::scoped_lock lk{m_lock};
|
std::scoped_lock lk{m_lock};
|
||||||
|
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({
|
||||||
if (m_data.empty()) {
|
if (m_data.empty()) {
|
||||||
m_event.Clear();
|
m_event.Clear();
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
R_UNLESS(!m_data.empty(), AM::ResultNoDataInChannel);
|
R_UNLESS(!m_data.empty(), AM::ResultNoDataInChannel);
|
||||||
|
|
||||||
|
@ -68,9 +68,7 @@ bool Process::Initialize(u64 program_id, u8 minimum_key_generation, u8 maximum_k
|
|||||||
Kernel::KProcess::Register(m_system.Kernel(), process);
|
Kernel::KProcess::Register(m_system.Kernel(), process);
|
||||||
|
|
||||||
// On exit, ensure we free the additional reference to the process.
|
// On exit, ensure we free the additional reference to the process.
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT({ process->Close(); });
|
||||||
process->Close();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Insert process modules into memory.
|
// Insert process modules into memory.
|
||||||
const auto [load_result, load_parameters] = app_loader->Load(*process, m_system);
|
const auto [load_result, load_parameters] = app_loader->Load(*process, m_system);
|
||||||
|
@ -123,13 +123,13 @@ Result IApplicationFunctions::EnsureSaveData(Out<u64> out_size, Common::UUID use
|
|||||||
LOG_INFO(Service_AM, "called, uid={}", user_id.FormattedString());
|
LOG_INFO(Service_AM, "called, uid={}", user_id.FormattedString());
|
||||||
|
|
||||||
FileSys::SaveDataAttribute attribute{};
|
FileSys::SaveDataAttribute attribute{};
|
||||||
attribute.program_id = m_applet->program_id;
|
attribute.title_id = m_applet->program_id;
|
||||||
attribute.user_id = user_id.AsU128();
|
attribute.user_id = user_id.AsU128();
|
||||||
attribute.type = FileSys::SaveDataType::Account;
|
attribute.type = FileSys::SaveDataType::SaveData;
|
||||||
|
|
||||||
FileSys::VirtualDir save_data{};
|
FileSys::VirtualDir save_data{};
|
||||||
R_TRY(system.GetFileSystemController().OpenSaveDataController()->CreateSaveData(
|
R_TRY(system.GetFileSystemController().OpenSaveDataController()->CreateSaveData(
|
||||||
&save_data, FileSys::SaveDataSpaceId::User, attribute));
|
&save_data, FileSys::SaveDataSpaceId::NandUser, attribute));
|
||||||
|
|
||||||
*out_size = 0;
|
*out_size = 0;
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
|
@ -1,223 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <numeric>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "common/logging/log.h"
|
|
||||||
#include "common/settings.h"
|
|
||||||
#include "core/core.h"
|
|
||||||
#include "core/file_sys/common_funcs.h"
|
|
||||||
#include "core/file_sys/content_archive.h"
|
|
||||||
#include "core/file_sys/control_metadata.h"
|
|
||||||
#include "core/file_sys/nca_metadata.h"
|
|
||||||
#include "core/file_sys/patch_manager.h"
|
|
||||||
#include "core/file_sys/registered_cache.h"
|
|
||||||
#include "core/hle/kernel/k_event.h"
|
|
||||||
#include "core/hle/service/aoc/addon_content_manager.h"
|
|
||||||
#include "core/hle/service/aoc/purchase_event_manager.h"
|
|
||||||
#include "core/hle/service/cmif_serialization.h"
|
|
||||||
#include "core/hle/service/ipc_helpers.h"
|
|
||||||
#include "core/hle/service/server_manager.h"
|
|
||||||
#include "core/loader/loader.h"
|
|
||||||
|
|
||||||
namespace Service::AOC {
|
|
||||||
|
|
||||||
static bool CheckAOCTitleIDMatchesBase(u64 title_id, u64 base) {
|
|
||||||
return FileSys::GetBaseTitleID(title_id) == base;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::vector<u64> AccumulateAOCTitleIDs(Core::System& system) {
|
|
||||||
std::vector<u64> add_on_content;
|
|
||||||
const auto& rcu = system.GetContentProvider();
|
|
||||||
const auto list =
|
|
||||||
rcu.ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
|
|
||||||
std::transform(list.begin(), list.end(), std::back_inserter(add_on_content),
|
|
||||||
[](const FileSys::ContentProviderEntry& rce) { return rce.title_id; });
|
|
||||||
add_on_content.erase(
|
|
||||||
std::remove_if(
|
|
||||||
add_on_content.begin(), add_on_content.end(),
|
|
||||||
[&rcu](u64 tid) {
|
|
||||||
return rcu.GetEntry(tid, FileSys::ContentRecordType::Data)->GetStatus() !=
|
|
||||||
Loader::ResultStatus::Success;
|
|
||||||
}),
|
|
||||||
add_on_content.end());
|
|
||||||
return add_on_content;
|
|
||||||
}
|
|
||||||
|
|
||||||
IAddOnContentManager::IAddOnContentManager(Core::System& system_)
|
|
||||||
: ServiceFramework{system_, "aoc:u"}, add_on_content{AccumulateAOCTitleIDs(system)},
|
|
||||||
service_context{system_, "aoc:u"} {
|
|
||||||
// clang-format off
|
|
||||||
static const FunctionInfo functions[] = {
|
|
||||||
{0, nullptr, "CountAddOnContentByApplicationId"},
|
|
||||||
{1, nullptr, "ListAddOnContentByApplicationId"},
|
|
||||||
{2, D<&IAddOnContentManager::CountAddOnContent>, "CountAddOnContent"},
|
|
||||||
{3, D<&IAddOnContentManager::ListAddOnContent>, "ListAddOnContent"},
|
|
||||||
{4, nullptr, "GetAddOnContentBaseIdByApplicationId"},
|
|
||||||
{5, D<&IAddOnContentManager::GetAddOnContentBaseId>, "GetAddOnContentBaseId"},
|
|
||||||
{6, nullptr, "PrepareAddOnContentByApplicationId"},
|
|
||||||
{7, D<&IAddOnContentManager::PrepareAddOnContent>, "PrepareAddOnContent"},
|
|
||||||
{8, D<&IAddOnContentManager::GetAddOnContentListChangedEvent>, "GetAddOnContentListChangedEvent"},
|
|
||||||
{9, nullptr, "GetAddOnContentLostErrorCode"},
|
|
||||||
{10, D<&IAddOnContentManager::GetAddOnContentListChangedEventWithProcessId>, "GetAddOnContentListChangedEventWithProcessId"},
|
|
||||||
{11, D<&IAddOnContentManager::NotifyMountAddOnContent>, "NotifyMountAddOnContent"},
|
|
||||||
{12, D<&IAddOnContentManager::NotifyUnmountAddOnContent>, "NotifyUnmountAddOnContent"},
|
|
||||||
{13, nullptr, "IsAddOnContentMountedForDebug"},
|
|
||||||
{50, D<&IAddOnContentManager::CheckAddOnContentMountStatus>, "CheckAddOnContentMountStatus"},
|
|
||||||
{100, D<&IAddOnContentManager::CreateEcPurchasedEventManager>, "CreateEcPurchasedEventManager"},
|
|
||||||
{101, D<&IAddOnContentManager::CreatePermanentEcPurchasedEventManager>, "CreatePermanentEcPurchasedEventManager"},
|
|
||||||
{110, nullptr, "CreateContentsServiceManager"},
|
|
||||||
{200, nullptr, "SetRequiredAddOnContentsOnContentsAvailabilityTransition"},
|
|
||||||
{300, nullptr, "SetupHostAddOnContent"},
|
|
||||||
{301, nullptr, "GetRegisteredAddOnContentPath"},
|
|
||||||
{302, nullptr, "UpdateCachedList"},
|
|
||||||
};
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
RegisterHandlers(functions);
|
|
||||||
|
|
||||||
aoc_change_event = service_context.CreateEvent("GetAddOnContentListChanged:Event");
|
|
||||||
}
|
|
||||||
|
|
||||||
IAddOnContentManager::~IAddOnContentManager() {
|
|
||||||
service_context.CloseEvent(aoc_change_event);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result IAddOnContentManager::CountAddOnContent(Out<u32> out_count, ClientProcessId process_id) {
|
|
||||||
LOG_DEBUG(Service_AOC, "called. process_id={}", process_id.pid);
|
|
||||||
|
|
||||||
const auto current = system.GetApplicationProcessProgramID();
|
|
||||||
|
|
||||||
const auto& disabled = Settings::values.disabled_addons[current];
|
|
||||||
if (std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end()) {
|
|
||||||
*out_count = 0;
|
|
||||||
R_SUCCEED();
|
|
||||||
}
|
|
||||||
|
|
||||||
*out_count = static_cast<u32>(
|
|
||||||
std::count_if(add_on_content.begin(), add_on_content.end(),
|
|
||||||
[current](u64 tid) { return CheckAOCTitleIDMatchesBase(tid, current); }));
|
|
||||||
|
|
||||||
R_SUCCEED();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result IAddOnContentManager::ListAddOnContent(Out<u32> out_count,
|
|
||||||
OutBuffer<BufferAttr_HipcMapAlias> out_addons,
|
|
||||||
u32 offset, u32 count, ClientProcessId process_id) {
|
|
||||||
LOG_DEBUG(Service_AOC, "called with offset={}, count={}, process_id={}", offset, count,
|
|
||||||
process_id.pid);
|
|
||||||
|
|
||||||
const auto current = FileSys::GetBaseTitleID(system.GetApplicationProcessProgramID());
|
|
||||||
|
|
||||||
std::vector<u32> out;
|
|
||||||
const auto& disabled = Settings::values.disabled_addons[current];
|
|
||||||
if (std::find(disabled.begin(), disabled.end(), "DLC") == disabled.end()) {
|
|
||||||
for (u64 content_id : add_on_content) {
|
|
||||||
if (FileSys::GetBaseTitleID(content_id) != current) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
out.push_back(static_cast<u32>(FileSys::GetAOCID(content_id)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(DarkLordZach): Find the correct error code.
|
|
||||||
R_UNLESS(out.size() >= offset, ResultUnknown);
|
|
||||||
|
|
||||||
*out_count = static_cast<u32>(std::min<size_t>(out.size() - offset, count));
|
|
||||||
std::rotate(out.begin(), out.begin() + offset, out.end());
|
|
||||||
|
|
||||||
std::memcpy(out_addons.data(), out.data(), *out_count);
|
|
||||||
|
|
||||||
R_SUCCEED();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result IAddOnContentManager::GetAddOnContentBaseId(Out<u64> out_title_id,
|
|
||||||
ClientProcessId process_id) {
|
|
||||||
LOG_DEBUG(Service_AOC, "called. process_id={}", process_id.pid);
|
|
||||||
|
|
||||||
const auto title_id = system.GetApplicationProcessProgramID();
|
|
||||||
const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
|
|
||||||
system.GetContentProvider()};
|
|
||||||
|
|
||||||
const auto res = pm.GetControlMetadata();
|
|
||||||
if (res.first == nullptr) {
|
|
||||||
*out_title_id = FileSys::GetAOCBaseTitleID(title_id);
|
|
||||||
R_SUCCEED();
|
|
||||||
}
|
|
||||||
|
|
||||||
*out_title_id = res.first->GetDLCBaseTitleId();
|
|
||||||
|
|
||||||
R_SUCCEED();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result IAddOnContentManager::PrepareAddOnContent(s32 addon_index, ClientProcessId process_id) {
|
|
||||||
LOG_WARNING(Service_AOC, "(STUBBED) called with addon_index={}, process_id={}", addon_index,
|
|
||||||
process_id.pid);
|
|
||||||
|
|
||||||
R_SUCCEED();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result IAddOnContentManager::GetAddOnContentListChangedEvent(
|
|
||||||
OutCopyHandle<Kernel::KReadableEvent> out_event) {
|
|
||||||
LOG_WARNING(Service_AOC, "(STUBBED) called");
|
|
||||||
|
|
||||||
*out_event = &aoc_change_event->GetReadableEvent();
|
|
||||||
|
|
||||||
R_SUCCEED();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result IAddOnContentManager::GetAddOnContentListChangedEventWithProcessId(
|
|
||||||
OutCopyHandle<Kernel::KReadableEvent> out_event, ClientProcessId process_id) {
|
|
||||||
LOG_WARNING(Service_AOC, "(STUBBED) called");
|
|
||||||
|
|
||||||
*out_event = &aoc_change_event->GetReadableEvent();
|
|
||||||
|
|
||||||
R_SUCCEED();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result IAddOnContentManager::NotifyMountAddOnContent() {
|
|
||||||
LOG_WARNING(Service_AOC, "(STUBBED) called");
|
|
||||||
|
|
||||||
R_SUCCEED();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result IAddOnContentManager::NotifyUnmountAddOnContent() {
|
|
||||||
LOG_WARNING(Service_AOC, "(STUBBED) called");
|
|
||||||
|
|
||||||
R_SUCCEED();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result IAddOnContentManager::CheckAddOnContentMountStatus() {
|
|
||||||
LOG_WARNING(Service_AOC, "(STUBBED) called");
|
|
||||||
|
|
||||||
R_SUCCEED();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result IAddOnContentManager::CreateEcPurchasedEventManager(
|
|
||||||
OutInterface<IPurchaseEventManager> out_interface) {
|
|
||||||
LOG_WARNING(Service_AOC, "(STUBBED) called");
|
|
||||||
|
|
||||||
*out_interface = std::make_shared<IPurchaseEventManager>(system);
|
|
||||||
|
|
||||||
R_SUCCEED();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result IAddOnContentManager::CreatePermanentEcPurchasedEventManager(
|
|
||||||
OutInterface<IPurchaseEventManager> out_interface) {
|
|
||||||
LOG_WARNING(Service_AOC, "(STUBBED) called");
|
|
||||||
|
|
||||||
*out_interface = std::make_shared<IPurchaseEventManager>(system);
|
|
||||||
|
|
||||||
R_SUCCEED();
|
|
||||||
}
|
|
||||||
|
|
||||||
void LoopProcess(Core::System& system) {
|
|
||||||
auto server_manager = std::make_unique<ServerManager>(system);
|
|
||||||
server_manager->RegisterNamedService("aoc:u", std::make_shared<IAddOnContentManager>(system));
|
|
||||||
ServerManager::RunServer(std::move(server_manager));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Service::AOC
|
|
@ -1,51 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "core/hle/service/cmif_types.h"
|
|
||||||
#include "core/hle/service/kernel_helpers.h"
|
|
||||||
#include "core/hle/service/service.h"
|
|
||||||
|
|
||||||
namespace Core {
|
|
||||||
class System;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Kernel {
|
|
||||||
class KEvent;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Service::AOC {
|
|
||||||
|
|
||||||
class IPurchaseEventManager;
|
|
||||||
|
|
||||||
class IAddOnContentManager final : public ServiceFramework<IAddOnContentManager> {
|
|
||||||
public:
|
|
||||||
explicit IAddOnContentManager(Core::System& system);
|
|
||||||
~IAddOnContentManager() override;
|
|
||||||
|
|
||||||
Result CountAddOnContent(Out<u32> out_count, ClientProcessId process_id);
|
|
||||||
Result ListAddOnContent(Out<u32> out_count, OutBuffer<BufferAttr_HipcMapAlias> out_addons,
|
|
||||||
u32 offset, u32 count, ClientProcessId process_id);
|
|
||||||
Result GetAddOnContentBaseId(Out<u64> out_title_id, ClientProcessId process_id);
|
|
||||||
Result PrepareAddOnContent(s32 addon_index, ClientProcessId process_id);
|
|
||||||
Result GetAddOnContentListChangedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
|
||||||
Result GetAddOnContentListChangedEventWithProcessId(
|
|
||||||
OutCopyHandle<Kernel::KReadableEvent> out_event, ClientProcessId process_id);
|
|
||||||
Result NotifyMountAddOnContent();
|
|
||||||
Result NotifyUnmountAddOnContent();
|
|
||||||
Result CheckAddOnContentMountStatus();
|
|
||||||
Result CreateEcPurchasedEventManager(OutInterface<IPurchaseEventManager> out_interface);
|
|
||||||
Result CreatePermanentEcPurchasedEventManager(
|
|
||||||
OutInterface<IPurchaseEventManager> out_interface);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<u64> add_on_content;
|
|
||||||
KernelHelpers::ServiceContext service_context;
|
|
||||||
|
|
||||||
Kernel::KEvent* aoc_change_event;
|
|
||||||
};
|
|
||||||
|
|
||||||
void LoopProcess(Core::System& system);
|
|
||||||
|
|
||||||
} // namespace Service::AOC
|
|
340
src/core/hle/service/aoc/aoc_u.cpp
Normal file
340
src/core/hle/service/aoc/aoc_u.cpp
Normal file
@ -0,0 +1,340 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <numeric>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "common/settings.h"
|
||||||
|
#include "core/core.h"
|
||||||
|
#include "core/file_sys/common_funcs.h"
|
||||||
|
#include "core/file_sys/content_archive.h"
|
||||||
|
#include "core/file_sys/control_metadata.h"
|
||||||
|
#include "core/file_sys/nca_metadata.h"
|
||||||
|
#include "core/file_sys/patch_manager.h"
|
||||||
|
#include "core/file_sys/registered_cache.h"
|
||||||
|
#include "core/hle/kernel/k_event.h"
|
||||||
|
#include "core/hle/service/aoc/aoc_u.h"
|
||||||
|
#include "core/hle/service/ipc_helpers.h"
|
||||||
|
#include "core/hle/service/server_manager.h"
|
||||||
|
#include "core/loader/loader.h"
|
||||||
|
|
||||||
|
namespace Service::AOC {
|
||||||
|
|
||||||
|
constexpr Result ResultNoPurchasedProductInfoAvailable{ErrorModule::NIMShop, 400};
|
||||||
|
|
||||||
|
static bool CheckAOCTitleIDMatchesBase(u64 title_id, u64 base) {
|
||||||
|
return FileSys::GetBaseTitleID(title_id) == base;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<u64> AccumulateAOCTitleIDs(Core::System& system) {
|
||||||
|
std::vector<u64> add_on_content;
|
||||||
|
const auto& rcu = system.GetContentProvider();
|
||||||
|
const auto list =
|
||||||
|
rcu.ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
|
||||||
|
std::transform(list.begin(), list.end(), std::back_inserter(add_on_content),
|
||||||
|
[](const FileSys::ContentProviderEntry& rce) { return rce.title_id; });
|
||||||
|
add_on_content.erase(
|
||||||
|
std::remove_if(
|
||||||
|
add_on_content.begin(), add_on_content.end(),
|
||||||
|
[&rcu](u64 tid) {
|
||||||
|
return rcu.GetEntry(tid, FileSys::ContentRecordType::Data)->GetStatus() !=
|
||||||
|
Loader::ResultStatus::Success;
|
||||||
|
}),
|
||||||
|
add_on_content.end());
|
||||||
|
return add_on_content;
|
||||||
|
}
|
||||||
|
|
||||||
|
class IPurchaseEventManager final : public ServiceFramework<IPurchaseEventManager> {
|
||||||
|
public:
|
||||||
|
explicit IPurchaseEventManager(Core::System& system_)
|
||||||
|
: ServiceFramework{system_, "IPurchaseEventManager"}, service_context{
|
||||||
|
system, "IPurchaseEventManager"} {
|
||||||
|
// clang-format off
|
||||||
|
static const FunctionInfo functions[] = {
|
||||||
|
{0, &IPurchaseEventManager::SetDefaultDeliveryTarget, "SetDefaultDeliveryTarget"},
|
||||||
|
{1, &IPurchaseEventManager::SetDeliveryTarget, "SetDeliveryTarget"},
|
||||||
|
{2, &IPurchaseEventManager::GetPurchasedEventReadableHandle, "GetPurchasedEventReadableHandle"},
|
||||||
|
{3, &IPurchaseEventManager::PopPurchasedProductInfo, "PopPurchasedProductInfo"},
|
||||||
|
{4, &IPurchaseEventManager::PopPurchasedProductInfoWithUid, "PopPurchasedProductInfoWithUid"},
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
RegisterHandlers(functions);
|
||||||
|
|
||||||
|
purchased_event = service_context.CreateEvent("IPurchaseEventManager:PurchasedEvent");
|
||||||
|
}
|
||||||
|
|
||||||
|
~IPurchaseEventManager() override {
|
||||||
|
service_context.CloseEvent(purchased_event);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void SetDefaultDeliveryTarget(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
|
||||||
|
const auto unknown_1 = rp.Pop<u64>();
|
||||||
|
[[maybe_unused]] const auto unknown_2 = ctx.ReadBuffer();
|
||||||
|
|
||||||
|
LOG_WARNING(Service_AOC, "(STUBBED) called, unknown_1={}", unknown_1);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetDeliveryTarget(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
|
||||||
|
const auto unknown_1 = rp.Pop<u64>();
|
||||||
|
[[maybe_unused]] const auto unknown_2 = ctx.ReadBuffer();
|
||||||
|
|
||||||
|
LOG_WARNING(Service_AOC, "(STUBBED) called, unknown_1={}", unknown_1);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetPurchasedEventReadableHandle(HLERequestContext& ctx) {
|
||||||
|
LOG_WARNING(Service_AOC, "called");
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.PushCopyObjects(purchased_event->GetReadableEvent());
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopPurchasedProductInfo(HLERequestContext& ctx) {
|
||||||
|
LOG_DEBUG(Service_AOC, "(STUBBED) called");
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ResultNoPurchasedProductInfoAvailable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopPurchasedProductInfoWithUid(HLERequestContext& ctx) {
|
||||||
|
LOG_DEBUG(Service_AOC, "(STUBBED) called");
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ResultNoPurchasedProductInfoAvailable);
|
||||||
|
}
|
||||||
|
|
||||||
|
KernelHelpers::ServiceContext service_context;
|
||||||
|
|
||||||
|
Kernel::KEvent* purchased_event;
|
||||||
|
};
|
||||||
|
|
||||||
|
AOC_U::AOC_U(Core::System& system_)
|
||||||
|
: ServiceFramework{system_, "aoc:u"}, add_on_content{AccumulateAOCTitleIDs(system)},
|
||||||
|
service_context{system_, "aoc:u"} {
|
||||||
|
// clang-format off
|
||||||
|
static const FunctionInfo functions[] = {
|
||||||
|
{0, nullptr, "CountAddOnContentByApplicationId"},
|
||||||
|
{1, nullptr, "ListAddOnContentByApplicationId"},
|
||||||
|
{2, &AOC_U::CountAddOnContent, "CountAddOnContent"},
|
||||||
|
{3, &AOC_U::ListAddOnContent, "ListAddOnContent"},
|
||||||
|
{4, nullptr, "GetAddOnContentBaseIdByApplicationId"},
|
||||||
|
{5, &AOC_U::GetAddOnContentBaseId, "GetAddOnContentBaseId"},
|
||||||
|
{6, nullptr, "PrepareAddOnContentByApplicationId"},
|
||||||
|
{7, &AOC_U::PrepareAddOnContent, "PrepareAddOnContent"},
|
||||||
|
{8, &AOC_U::GetAddOnContentListChangedEvent, "GetAddOnContentListChangedEvent"},
|
||||||
|
{9, nullptr, "GetAddOnContentLostErrorCode"},
|
||||||
|
{10, &AOC_U::GetAddOnContentListChangedEventWithProcessId, "GetAddOnContentListChangedEventWithProcessId"},
|
||||||
|
{11, &AOC_U::NotifyMountAddOnContent, "NotifyMountAddOnContent"},
|
||||||
|
{12, &AOC_U::NotifyUnmountAddOnContent, "NotifyUnmountAddOnContent"},
|
||||||
|
{13, nullptr, "IsAddOnContentMountedForDebug"},
|
||||||
|
{50, &AOC_U::CheckAddOnContentMountStatus, "CheckAddOnContentMountStatus"},
|
||||||
|
{100, &AOC_U::CreateEcPurchasedEventManager, "CreateEcPurchasedEventManager"},
|
||||||
|
{101, &AOC_U::CreatePermanentEcPurchasedEventManager, "CreatePermanentEcPurchasedEventManager"},
|
||||||
|
{110, nullptr, "CreateContentsServiceManager"},
|
||||||
|
{200, nullptr, "SetRequiredAddOnContentsOnContentsAvailabilityTransition"},
|
||||||
|
{300, nullptr, "SetupHostAddOnContent"},
|
||||||
|
{301, nullptr, "GetRegisteredAddOnContentPath"},
|
||||||
|
{302, nullptr, "UpdateCachedList"},
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
RegisterHandlers(functions);
|
||||||
|
|
||||||
|
aoc_change_event = service_context.CreateEvent("GetAddOnContentListChanged:Event");
|
||||||
|
}
|
||||||
|
|
||||||
|
AOC_U::~AOC_U() {
|
||||||
|
service_context.CloseEvent(aoc_change_event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AOC_U::CountAddOnContent(HLERequestContext& ctx) {
|
||||||
|
struct Parameters {
|
||||||
|
u64 process_id;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(Parameters) == 8);
|
||||||
|
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto params = rp.PopRaw<Parameters>();
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_AOC, "called. process_id={}", params.process_id);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
|
||||||
|
const auto current = system.GetApplicationProcessProgramID();
|
||||||
|
|
||||||
|
const auto& disabled = Settings::values.disabled_addons[current];
|
||||||
|
if (std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end()) {
|
||||||
|
rb.Push<u32>(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rb.Push<u32>(static_cast<u32>(
|
||||||
|
std::count_if(add_on_content.begin(), add_on_content.end(),
|
||||||
|
[current](u64 tid) { return CheckAOCTitleIDMatchesBase(tid, current); })));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AOC_U::ListAddOnContent(HLERequestContext& ctx) {
|
||||||
|
struct Parameters {
|
||||||
|
u32 offset;
|
||||||
|
u32 count;
|
||||||
|
u64 process_id;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(Parameters) == 16);
|
||||||
|
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto [offset, count, process_id] = rp.PopRaw<Parameters>();
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_AOC, "called with offset={}, count={}, process_id={}", offset, count,
|
||||||
|
process_id);
|
||||||
|
|
||||||
|
const auto current = FileSys::GetBaseTitleID(system.GetApplicationProcessProgramID());
|
||||||
|
|
||||||
|
std::vector<u32> out;
|
||||||
|
const auto& disabled = Settings::values.disabled_addons[current];
|
||||||
|
if (std::find(disabled.begin(), disabled.end(), "DLC") == disabled.end()) {
|
||||||
|
for (u64 content_id : add_on_content) {
|
||||||
|
if (FileSys::GetBaseTitleID(content_id) != current) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
out.push_back(static_cast<u32>(FileSys::GetAOCID(content_id)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out.size() < offset) {
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
// TODO(DarkLordZach): Find the correct error code.
|
||||||
|
rb.Push(ResultUnknown);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto out_count = static_cast<u32>(std::min<size_t>(out.size() - offset, count));
|
||||||
|
std::rotate(out.begin(), out.begin() + offset, out.end());
|
||||||
|
out.resize(out_count);
|
||||||
|
|
||||||
|
ctx.WriteBuffer(out);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.Push(out_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AOC_U::GetAddOnContentBaseId(HLERequestContext& ctx) {
|
||||||
|
struct Parameters {
|
||||||
|
u64 process_id;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(Parameters) == 8);
|
||||||
|
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto params = rp.PopRaw<Parameters>();
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_AOC, "called. process_id={}", params.process_id);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 4};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
|
||||||
|
const auto title_id = system.GetApplicationProcessProgramID();
|
||||||
|
const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
|
||||||
|
system.GetContentProvider()};
|
||||||
|
|
||||||
|
const auto res = pm.GetControlMetadata();
|
||||||
|
if (res.first == nullptr) {
|
||||||
|
rb.Push(FileSys::GetAOCBaseTitleID(title_id));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rb.Push(res.first->GetDLCBaseTitleId());
|
||||||
|
}
|
||||||
|
|
||||||
|
void AOC_U::PrepareAddOnContent(HLERequestContext& ctx) {
|
||||||
|
struct Parameters {
|
||||||
|
s32 addon_index;
|
||||||
|
u64 process_id;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(Parameters) == 16);
|
||||||
|
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto [addon_index, process_id] = rp.PopRaw<Parameters>();
|
||||||
|
|
||||||
|
LOG_WARNING(Service_AOC, "(STUBBED) called with addon_index={}, process_id={}", addon_index,
|
||||||
|
process_id);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AOC_U::GetAddOnContentListChangedEvent(HLERequestContext& ctx) {
|
||||||
|
LOG_WARNING(Service_AOC, "(STUBBED) called");
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.PushCopyObjects(aoc_change_event->GetReadableEvent());
|
||||||
|
}
|
||||||
|
|
||||||
|
void AOC_U::GetAddOnContentListChangedEventWithProcessId(HLERequestContext& ctx) {
|
||||||
|
LOG_WARNING(Service_AOC, "(STUBBED) called");
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.PushCopyObjects(aoc_change_event->GetReadableEvent());
|
||||||
|
}
|
||||||
|
|
||||||
|
void AOC_U::NotifyMountAddOnContent(HLERequestContext& ctx) {
|
||||||
|
LOG_WARNING(Service_AOC, "(STUBBED) called");
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AOC_U::NotifyUnmountAddOnContent(HLERequestContext& ctx) {
|
||||||
|
LOG_WARNING(Service_AOC, "(STUBBED) called");
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AOC_U::CheckAddOnContentMountStatus(HLERequestContext& ctx) {
|
||||||
|
LOG_WARNING(Service_AOC, "(STUBBED) called");
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AOC_U::CreateEcPurchasedEventManager(HLERequestContext& ctx) {
|
||||||
|
LOG_WARNING(Service_AOC, "(STUBBED) called");
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.PushIpcInterface<IPurchaseEventManager>(system);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AOC_U::CreatePermanentEcPurchasedEventManager(HLERequestContext& ctx) {
|
||||||
|
LOG_WARNING(Service_AOC, "(STUBBED) called");
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.PushIpcInterface<IPurchaseEventManager>(system);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoopProcess(Core::System& system) {
|
||||||
|
auto server_manager = std::make_unique<ServerManager>(system);
|
||||||
|
server_manager->RegisterNamedService("aoc:u", std::make_shared<AOC_U>(system));
|
||||||
|
ServerManager::RunServer(std::move(server_manager));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Service::AOC
|
45
src/core/hle/service/aoc/aoc_u.h
Normal file
45
src/core/hle/service/aoc/aoc_u.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/service/kernel_helpers.h"
|
||||||
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
class KEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Service::AOC {
|
||||||
|
|
||||||
|
class AOC_U final : public ServiceFramework<AOC_U> {
|
||||||
|
public:
|
||||||
|
explicit AOC_U(Core::System& system);
|
||||||
|
~AOC_U() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void CountAddOnContent(HLERequestContext& ctx);
|
||||||
|
void ListAddOnContent(HLERequestContext& ctx);
|
||||||
|
void GetAddOnContentBaseId(HLERequestContext& ctx);
|
||||||
|
void PrepareAddOnContent(HLERequestContext& ctx);
|
||||||
|
void GetAddOnContentListChangedEvent(HLERequestContext& ctx);
|
||||||
|
void GetAddOnContentListChangedEventWithProcessId(HLERequestContext& ctx);
|
||||||
|
void NotifyMountAddOnContent(HLERequestContext& ctx);
|
||||||
|
void NotifyUnmountAddOnContent(HLERequestContext& ctx);
|
||||||
|
void CheckAddOnContentMountStatus(HLERequestContext& ctx);
|
||||||
|
void CreateEcPurchasedEventManager(HLERequestContext& ctx);
|
||||||
|
void CreatePermanentEcPurchasedEventManager(HLERequestContext& ctx);
|
||||||
|
|
||||||
|
std::vector<u64> add_on_content;
|
||||||
|
KernelHelpers::ServiceContext service_context;
|
||||||
|
|
||||||
|
Kernel::KEvent* aoc_change_event;
|
||||||
|
};
|
||||||
|
|
||||||
|
void LoopProcess(Core::System& system);
|
||||||
|
|
||||||
|
} // namespace Service::AOC
|
@ -1,67 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include "core/hle/service/aoc/purchase_event_manager.h"
|
|
||||||
#include "core/hle/service/cmif_serialization.h"
|
|
||||||
|
|
||||||
namespace Service::AOC {
|
|
||||||
|
|
||||||
constexpr Result ResultNoPurchasedProductInfoAvailable{ErrorModule::NIMShop, 400};
|
|
||||||
|
|
||||||
IPurchaseEventManager::IPurchaseEventManager(Core::System& system_)
|
|
||||||
: ServiceFramework{system_, "IPurchaseEventManager"}, service_context{system,
|
|
||||||
"IPurchaseEventManager"} {
|
|
||||||
// clang-format off
|
|
||||||
static const FunctionInfo functions[] = {
|
|
||||||
{0, D<&IPurchaseEventManager::SetDefaultDeliveryTarget>, "SetDefaultDeliveryTarget"},
|
|
||||||
{1, D<&IPurchaseEventManager::SetDeliveryTarget>, "SetDeliveryTarget"},
|
|
||||||
{2, D<&IPurchaseEventManager::GetPurchasedEvent>, "GetPurchasedEvent"},
|
|
||||||
{3, D<&IPurchaseEventManager::PopPurchasedProductInfo>, "PopPurchasedProductInfo"},
|
|
||||||
{4, D<&IPurchaseEventManager::PopPurchasedProductInfoWithUid>, "PopPurchasedProductInfoWithUid"},
|
|
||||||
};
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
RegisterHandlers(functions);
|
|
||||||
|
|
||||||
purchased_event = service_context.CreateEvent("IPurchaseEventManager:PurchasedEvent");
|
|
||||||
}
|
|
||||||
|
|
||||||
IPurchaseEventManager::~IPurchaseEventManager() {
|
|
||||||
service_context.CloseEvent(purchased_event);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result IPurchaseEventManager::SetDefaultDeliveryTarget(
|
|
||||||
ClientProcessId process_id, InBuffer<BufferAttr_HipcMapAlias> in_buffer) {
|
|
||||||
LOG_WARNING(Service_AOC, "(STUBBED) called, process_id={}", process_id.pid);
|
|
||||||
|
|
||||||
R_SUCCEED();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result IPurchaseEventManager::SetDeliveryTarget(u64 unknown,
|
|
||||||
InBuffer<BufferAttr_HipcMapAlias> in_buffer) {
|
|
||||||
LOG_WARNING(Service_AOC, "(STUBBED) called, unknown={}", unknown);
|
|
||||||
|
|
||||||
R_SUCCEED();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result IPurchaseEventManager::GetPurchasedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
|
|
||||||
LOG_WARNING(Service_AOC, "called");
|
|
||||||
|
|
||||||
*out_event = &purchased_event->GetReadableEvent();
|
|
||||||
|
|
||||||
R_SUCCEED();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result IPurchaseEventManager::PopPurchasedProductInfo() {
|
|
||||||
LOG_DEBUG(Service_AOC, "(STUBBED) called");
|
|
||||||
|
|
||||||
R_RETURN(ResultNoPurchasedProductInfoAvailable);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result IPurchaseEventManager::PopPurchasedProductInfoWithUid() {
|
|
||||||
LOG_DEBUG(Service_AOC, "(STUBBED) called");
|
|
||||||
|
|
||||||
R_RETURN(ResultNoPurchasedProductInfoAvailable);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Service::AOC
|
|
@ -1,30 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "core/hle/service/cmif_types.h"
|
|
||||||
#include "core/hle/service/kernel_helpers.h"
|
|
||||||
#include "core/hle/service/os/event.h"
|
|
||||||
#include "core/hle/service/service.h"
|
|
||||||
|
|
||||||
namespace Service::AOC {
|
|
||||||
|
|
||||||
class IPurchaseEventManager final : public ServiceFramework<IPurchaseEventManager> {
|
|
||||||
public:
|
|
||||||
explicit IPurchaseEventManager(Core::System& system_);
|
|
||||||
~IPurchaseEventManager() override;
|
|
||||||
|
|
||||||
Result SetDefaultDeliveryTarget(ClientProcessId process_id,
|
|
||||||
InBuffer<BufferAttr_HipcMapAlias> in_buffer);
|
|
||||||
Result SetDeliveryTarget(u64 unknown, InBuffer<BufferAttr_HipcMapAlias> in_buffer);
|
|
||||||
Result GetPurchasedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
|
||||||
Result PopPurchasedProductInfo();
|
|
||||||
Result PopPurchasedProductInfoWithUid();
|
|
||||||
|
|
||||||
private:
|
|
||||||
KernelHelpers::ServiceContext service_context;
|
|
||||||
Kernel::KEvent* purchased_event;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Service::AOC
|
|
393
src/core/hle/service/audio/audin_u.cpp
Normal file
393
src/core/hle/service/audio/audin_u.cpp
Normal file
@ -0,0 +1,393 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "audio_core/in/audio_in_system.h"
|
||||||
|
#include "audio_core/renderer/audio_device.h"
|
||||||
|
#include "common/common_funcs.h"
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "common/scratch_buffer.h"
|
||||||
|
#include "common/string_util.h"
|
||||||
|
#include "core/core.h"
|
||||||
|
#include "core/hle/kernel/k_event.h"
|
||||||
|
#include "core/hle/service/audio/audin_u.h"
|
||||||
|
#include "core/hle/service/ipc_helpers.h"
|
||||||
|
|
||||||
|
namespace Service::Audio {
|
||||||
|
using namespace AudioCore::AudioIn;
|
||||||
|
|
||||||
|
class IAudioIn final : public ServiceFramework<IAudioIn> {
|
||||||
|
public:
|
||||||
|
explicit IAudioIn(Core::System& system_, Manager& manager, size_t session_id,
|
||||||
|
const std::string& device_name, const AudioInParameter& in_params,
|
||||||
|
Kernel::KProcess* handle, u64 applet_resource_user_id)
|
||||||
|
: ServiceFramework{system_, "IAudioIn"},
|
||||||
|
service_context{system_, "IAudioIn"}, event{service_context.CreateEvent("AudioInEvent")},
|
||||||
|
process{handle}, impl{std::make_shared<In>(system_, manager, event, session_id)} {
|
||||||
|
// clang-format off
|
||||||
|
static const FunctionInfo functions[] = {
|
||||||
|
{0, &IAudioIn::GetAudioInState, "GetAudioInState"},
|
||||||
|
{1, &IAudioIn::Start, "Start"},
|
||||||
|
{2, &IAudioIn::Stop, "Stop"},
|
||||||
|
{3, &IAudioIn::AppendAudioInBuffer, "AppendAudioInBuffer"},
|
||||||
|
{4, &IAudioIn::RegisterBufferEvent, "RegisterBufferEvent"},
|
||||||
|
{5, &IAudioIn::GetReleasedAudioInBuffer, "GetReleasedAudioInBuffer"},
|
||||||
|
{6, &IAudioIn::ContainsAudioInBuffer, "ContainsAudioInBuffer"},
|
||||||
|
{7, &IAudioIn::AppendAudioInBuffer, "AppendUacInBuffer"},
|
||||||
|
{8, &IAudioIn::AppendAudioInBuffer, "AppendAudioInBufferAuto"},
|
||||||
|
{9, &IAudioIn::GetReleasedAudioInBuffer, "GetReleasedAudioInBuffersAuto"},
|
||||||
|
{10, &IAudioIn::AppendAudioInBuffer, "AppendUacInBufferAuto"},
|
||||||
|
{11, &IAudioIn::GetAudioInBufferCount, "GetAudioInBufferCount"},
|
||||||
|
{12, &IAudioIn::SetDeviceGain, "SetDeviceGain"},
|
||||||
|
{13, &IAudioIn::GetDeviceGain, "GetDeviceGain"},
|
||||||
|
{14, &IAudioIn::FlushAudioInBuffers, "FlushAudioInBuffers"},
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
RegisterHandlers(functions);
|
||||||
|
|
||||||
|
process->Open();
|
||||||
|
|
||||||
|
if (impl->GetSystem()
|
||||||
|
.Initialize(device_name, in_params, handle, applet_resource_user_id)
|
||||||
|
.IsError()) {
|
||||||
|
LOG_ERROR(Service_Audio, "Failed to initialize the AudioIn System!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~IAudioIn() override {
|
||||||
|
impl->Free();
|
||||||
|
service_context.CloseEvent(event);
|
||||||
|
process->Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] std::shared_ptr<In> GetImpl() {
|
||||||
|
return impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void GetAudioInState(HLERequestContext& ctx) {
|
||||||
|
const auto state = static_cast<u32>(impl->GetState());
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_Audio, "called. State={}", state);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.Push(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Start(HLERequestContext& ctx) {
|
||||||
|
LOG_DEBUG(Service_Audio, "called");
|
||||||
|
|
||||||
|
auto result = impl->StartSystem();
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stop(HLERequestContext& ctx) {
|
||||||
|
LOG_DEBUG(Service_Audio, "called");
|
||||||
|
|
||||||
|
auto result = impl->StopSystem();
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppendAudioInBuffer(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
u64 tag = rp.PopRaw<u64>();
|
||||||
|
|
||||||
|
const auto in_buffer_size{ctx.GetReadBufferSize()};
|
||||||
|
if (in_buffer_size < sizeof(AudioInBuffer)) {
|
||||||
|
LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioInBuffer!");
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& in_buffer = ctx.ReadBuffer();
|
||||||
|
AudioInBuffer buffer{};
|
||||||
|
std::memcpy(&buffer, in_buffer.data(), sizeof(AudioInBuffer));
|
||||||
|
|
||||||
|
[[maybe_unused]] auto sessionid{impl->GetSystem().GetSessionId()};
|
||||||
|
LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}", sessionid, tag);
|
||||||
|
|
||||||
|
auto result = impl->AppendBuffer(buffer, tag);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegisterBufferEvent(HLERequestContext& ctx) {
|
||||||
|
LOG_DEBUG(Service_Audio, "called");
|
||||||
|
|
||||||
|
auto& buffer_event = impl->GetBufferEvent();
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.PushCopyObjects(buffer_event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetReleasedAudioInBuffer(HLERequestContext& ctx) {
|
||||||
|
const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>();
|
||||||
|
released_buffer.resize_destructive(write_buffer_size);
|
||||||
|
released_buffer[0] = 0;
|
||||||
|
|
||||||
|
const auto count = impl->GetReleasedBuffers(released_buffer);
|
||||||
|
|
||||||
|
LOG_TRACE(Service_Audio, "called. Session {} released {} buffers",
|
||||||
|
impl->GetSystem().GetSessionId(), count);
|
||||||
|
|
||||||
|
ctx.WriteBuffer(released_buffer);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.Push(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContainsAudioInBuffer(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
|
||||||
|
const u64 tag{rp.Pop<u64>()};
|
||||||
|
const auto buffer_queued{impl->ContainsAudioBuffer(tag)};
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_Audio, "called. Is buffer {:08X} registered? {}", tag, buffer_queued);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.Push(buffer_queued);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetAudioInBufferCount(HLERequestContext& ctx) {
|
||||||
|
const auto buffer_count = impl->GetBufferCount();
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_Audio, "called. Buffer count={}", buffer_count);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.Push(buffer_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetDeviceGain(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
|
||||||
|
const auto volume{rp.Pop<f32>()};
|
||||||
|
LOG_DEBUG(Service_Audio, "called. Gain {}", volume);
|
||||||
|
|
||||||
|
impl->SetVolume(volume);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetDeviceGain(HLERequestContext& ctx) {
|
||||||
|
auto volume{impl->GetVolume()};
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_Audio, "called. Gain {}", volume);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.Push(volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlushAudioInBuffers(HLERequestContext& ctx) {
|
||||||
|
bool flushed{impl->FlushAudioInBuffers()};
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_Audio, "called. Were any buffers flushed? {}", flushed);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.Push(flushed);
|
||||||
|
}
|
||||||
|
|
||||||
|
KernelHelpers::ServiceContext service_context;
|
||||||
|
Kernel::KEvent* event;
|
||||||
|
Kernel::KProcess* process;
|
||||||
|
std::shared_ptr<AudioCore::AudioIn::In> impl;
|
||||||
|
Common::ScratchBuffer<u64> released_buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
AudInU::AudInU(Core::System& system_)
|
||||||
|
: ServiceFramework{system_, "audin:u"}, service_context{system_, "AudInU"},
|
||||||
|
impl{std::make_unique<AudioCore::AudioIn::Manager>(system_)} {
|
||||||
|
// clang-format off
|
||||||
|
static const FunctionInfo functions[] = {
|
||||||
|
{0, &AudInU::ListAudioIns, "ListAudioIns"},
|
||||||
|
{1, &AudInU::OpenAudioIn, "OpenAudioIn"},
|
||||||
|
{2, &AudInU::ListAudioIns, "ListAudioInsAuto"},
|
||||||
|
{3, &AudInU::OpenAudioIn, "OpenAudioInAuto"},
|
||||||
|
{4, &AudInU::ListAudioInsAutoFiltered, "ListAudioInsAutoFiltered"},
|
||||||
|
{5, &AudInU::OpenAudioInProtocolSpecified, "OpenAudioInProtocolSpecified"},
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
RegisterHandlers(functions);
|
||||||
|
}
|
||||||
|
|
||||||
|
AudInU::~AudInU() = default;
|
||||||
|
|
||||||
|
void AudInU::ListAudioIns(HLERequestContext& ctx) {
|
||||||
|
using namespace AudioCore::Renderer;
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_Audio, "called");
|
||||||
|
|
||||||
|
const auto write_count =
|
||||||
|
static_cast<u32>(ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>());
|
||||||
|
std::vector<AudioDevice::AudioDeviceName> device_names{};
|
||||||
|
|
||||||
|
u32 out_count{0};
|
||||||
|
if (write_count > 0) {
|
||||||
|
out_count = impl->GetDeviceNames(device_names, write_count, false);
|
||||||
|
ctx.WriteBuffer(device_names);
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.Push(out_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudInU::ListAudioInsAutoFiltered(HLERequestContext& ctx) {
|
||||||
|
using namespace AudioCore::Renderer;
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_Audio, "called");
|
||||||
|
|
||||||
|
const auto write_count =
|
||||||
|
static_cast<u32>(ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>());
|
||||||
|
std::vector<AudioDevice::AudioDeviceName> device_names{};
|
||||||
|
|
||||||
|
u32 out_count{0};
|
||||||
|
if (write_count > 0) {
|
||||||
|
out_count = impl->GetDeviceNames(device_names, write_count, true);
|
||||||
|
ctx.WriteBuffer(device_names);
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.Push(out_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudInU::OpenAudioIn(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
auto in_params{rp.PopRaw<AudioInParameter>()};
|
||||||
|
auto applet_resource_user_id{rp.PopRaw<u64>()};
|
||||||
|
const auto device_name_data{ctx.ReadBuffer()};
|
||||||
|
auto device_name = Common::StringFromBuffer(device_name_data);
|
||||||
|
auto handle{ctx.GetCopyHandle(0)};
|
||||||
|
|
||||||
|
auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)};
|
||||||
|
if (process.IsNull()) {
|
||||||
|
LOG_ERROR(Service_Audio, "Failed to get process handle");
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ResultUnknown);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::scoped_lock l{impl->mutex};
|
||||||
|
auto link{impl->LinkToManager()};
|
||||||
|
if (link.IsError()) {
|
||||||
|
LOG_ERROR(Service_Audio, "Failed to link Audio In to Audio Manager");
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(link);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t new_session_id{};
|
||||||
|
auto result{impl->AcquireSessionId(new_session_id)};
|
||||||
|
if (result.IsError()) {
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_Audio, "Opening new AudioIn, sessionid={}, free sessions={}", new_session_id,
|
||||||
|
impl->num_free_sessions);
|
||||||
|
|
||||||
|
auto audio_in =
|
||||||
|
std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name, in_params,
|
||||||
|
process.GetPointerUnsafe(), applet_resource_user_id);
|
||||||
|
impl->sessions[new_session_id] = audio_in->GetImpl();
|
||||||
|
impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id;
|
||||||
|
|
||||||
|
auto& out_system = impl->sessions[new_session_id]->GetSystem();
|
||||||
|
AudioInParameterInternal out_params{.sample_rate = out_system.GetSampleRate(),
|
||||||
|
.channel_count = out_system.GetChannelCount(),
|
||||||
|
.sample_format =
|
||||||
|
static_cast<u32>(out_system.GetSampleFormat()),
|
||||||
|
.state = static_cast<u32>(out_system.GetState())};
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 6, 0, 1};
|
||||||
|
|
||||||
|
std::string out_name{out_system.GetName()};
|
||||||
|
ctx.WriteBuffer(out_name);
|
||||||
|
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.PushRaw<AudioInParameterInternal>(out_params);
|
||||||
|
rb.PushIpcInterface<IAudioIn>(audio_in);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudInU::OpenAudioInProtocolSpecified(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
auto protocol_specified{rp.PopRaw<u64>()};
|
||||||
|
auto in_params{rp.PopRaw<AudioInParameter>()};
|
||||||
|
auto applet_resource_user_id{rp.PopRaw<u64>()};
|
||||||
|
const auto device_name_data{ctx.ReadBuffer()};
|
||||||
|
auto device_name = Common::StringFromBuffer(device_name_data);
|
||||||
|
auto handle{ctx.GetCopyHandle(0)};
|
||||||
|
|
||||||
|
auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)};
|
||||||
|
if (process.IsNull()) {
|
||||||
|
LOG_ERROR(Service_Audio, "Failed to get process handle");
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ResultUnknown);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::scoped_lock l{impl->mutex};
|
||||||
|
auto link{impl->LinkToManager()};
|
||||||
|
if (link.IsError()) {
|
||||||
|
LOG_ERROR(Service_Audio, "Failed to link Audio In to Audio Manager");
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(link);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t new_session_id{};
|
||||||
|
auto result{impl->AcquireSessionId(new_session_id)};
|
||||||
|
if (result.IsError()) {
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_Audio, "Opening new AudioIn, sessionid={}, free sessions={}", new_session_id,
|
||||||
|
impl->num_free_sessions);
|
||||||
|
|
||||||
|
auto audio_in =
|
||||||
|
std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name, in_params,
|
||||||
|
process.GetPointerUnsafe(), applet_resource_user_id);
|
||||||
|
impl->sessions[new_session_id] = audio_in->GetImpl();
|
||||||
|
impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id;
|
||||||
|
|
||||||
|
auto& out_system = impl->sessions[new_session_id]->GetSystem();
|
||||||
|
AudioInParameterInternal out_params{.sample_rate = out_system.GetSampleRate(),
|
||||||
|
.channel_count = out_system.GetChannelCount(),
|
||||||
|
.sample_format =
|
||||||
|
static_cast<u32>(out_system.GetSampleFormat()),
|
||||||
|
.state = static_cast<u32>(out_system.GetState())};
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 6, 0, 1};
|
||||||
|
|
||||||
|
std::string out_name{out_system.GetName()};
|
||||||
|
if (protocol_specified == 0) {
|
||||||
|
if (out_system.IsUac()) {
|
||||||
|
out_name = "UacIn";
|
||||||
|
} else {
|
||||||
|
out_name = "DeviceIn";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.WriteBuffer(out_name);
|
||||||
|
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.PushRaw<AudioInParameterInternal>(out_params);
|
||||||
|
rb.PushIpcInterface<IAudioIn>(audio_in);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Service::Audio
|
38
src/core/hle/service/audio/audin_u.h
Normal file
38
src/core/hle/service/audio/audin_u.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "audio_core/audio_in_manager.h"
|
||||||
|
#include "audio_core/in/audio_in.h"
|
||||||
|
#include "core/hle/service/kernel_helpers.h"
|
||||||
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace AudioCore::AudioOut {
|
||||||
|
class Manager;
|
||||||
|
class In;
|
||||||
|
} // namespace AudioCore::AudioOut
|
||||||
|
|
||||||
|
namespace Service::Audio {
|
||||||
|
|
||||||
|
class AudInU final : public ServiceFramework<AudInU> {
|
||||||
|
public:
|
||||||
|
explicit AudInU(Core::System& system_);
|
||||||
|
~AudInU() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void ListAudioIns(HLERequestContext& ctx);
|
||||||
|
void ListAudioInsAutoFiltered(HLERequestContext& ctx);
|
||||||
|
void OpenInOutImpl(HLERequestContext& ctx);
|
||||||
|
void OpenAudioIn(HLERequestContext& ctx);
|
||||||
|
void OpenAudioInProtocolSpecified(HLERequestContext& ctx);
|
||||||
|
|
||||||
|
KernelHelpers::ServiceContext service_context;
|
||||||
|
std::unique_ptr<AudioCore::AudioIn::Manager> impl;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::Audio
|
@ -2,14 +2,14 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
|
#include "core/hle/service/audio/audin_u.h"
|
||||||
#include "core/hle/service/audio/audio.h"
|
#include "core/hle/service/audio/audio.h"
|
||||||
#include "core/hle/service/audio/audio_controller.h"
|
#include "core/hle/service/audio/audio_controller.h"
|
||||||
#include "core/hle/service/audio/audio_in_manager.h"
|
#include "core/hle/service/audio/audout_u.h"
|
||||||
#include "core/hle/service/audio/audio_out_manager.h"
|
#include "core/hle/service/audio/audrec_a.h"
|
||||||
#include "core/hle/service/audio/audio_renderer_manager.h"
|
#include "core/hle/service/audio/audrec_u.h"
|
||||||
#include "core/hle/service/audio/final_output_recorder_manager.h"
|
#include "core/hle/service/audio/audren_u.h"
|
||||||
#include "core/hle/service/audio/final_output_recorder_manager_for_applet.h"
|
#include "core/hle/service/audio/hwopus.h"
|
||||||
#include "core/hle/service/audio/hardware_opus_decoder_manager.h"
|
|
||||||
#include "core/hle/service/server_manager.h"
|
#include "core/hle/service/server_manager.h"
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
@ -19,16 +19,12 @@ void LoopProcess(Core::System& system) {
|
|||||||
auto server_manager = std::make_unique<ServerManager>(system);
|
auto server_manager = std::make_unique<ServerManager>(system);
|
||||||
|
|
||||||
server_manager->RegisterNamedService("audctl", std::make_shared<IAudioController>(system));
|
server_manager->RegisterNamedService("audctl", std::make_shared<IAudioController>(system));
|
||||||
server_manager->RegisterNamedService("audin:u", std::make_shared<IAudioInManager>(system));
|
server_manager->RegisterNamedService("audout:u", std::make_shared<AudOutU>(system));
|
||||||
server_manager->RegisterNamedService("audout:u", std::make_shared<IAudioOutManager>(system));
|
server_manager->RegisterNamedService("audin:u", std::make_shared<AudInU>(system));
|
||||||
server_manager->RegisterNamedService(
|
server_manager->RegisterNamedService("audrec:a", std::make_shared<AudRecA>(system));
|
||||||
"audrec:a", std::make_shared<IFinalOutputRecorderManagerForApplet>(system));
|
server_manager->RegisterNamedService("audrec:u", std::make_shared<AudRecU>(system));
|
||||||
server_manager->RegisterNamedService("audrec:u",
|
server_manager->RegisterNamedService("audren:u", std::make_shared<AudRenU>(system));
|
||||||
std::make_shared<IFinalOutputRecorderManager>(system));
|
server_manager->RegisterNamedService("hwopus", std::make_shared<HwOpus>(system));
|
||||||
server_manager->RegisterNamedService("audren:u",
|
|
||||||
std::make_shared<IAudioRendererManager>(system));
|
|
||||||
server_manager->RegisterNamedService("hwopus",
|
|
||||||
std::make_shared<IHardwareOpusDecoderManager>(system));
|
|
||||||
ServerManager::RunServer(std::move(server_manager));
|
ServerManager::RunServer(std::move(server_manager));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,27 +16,27 @@ IAudioController::IAudioController(Core::System& system_)
|
|||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, nullptr, "GetTargetVolume"},
|
{0, nullptr, "GetTargetVolume"},
|
||||||
{1, nullptr, "SetTargetVolume"},
|
{1, nullptr, "SetTargetVolume"},
|
||||||
{2, D<&IAudioController::GetTargetVolumeMin>, "GetTargetVolumeMin"},
|
{2, C<&IAudioController::GetTargetVolumeMin>, "GetTargetVolumeMin"},
|
||||||
{3, D<&IAudioController::GetTargetVolumeMax>, "GetTargetVolumeMax"},
|
{3, C<&IAudioController::GetTargetVolumeMax>, "GetTargetVolumeMax"},
|
||||||
{4, nullptr, "IsTargetMute"},
|
{4, nullptr, "IsTargetMute"},
|
||||||
{5, nullptr, "SetTargetMute"},
|
{5, nullptr, "SetTargetMute"},
|
||||||
{6, nullptr, "IsTargetConnected"},
|
{6, nullptr, "IsTargetConnected"},
|
||||||
{7, nullptr, "SetDefaultTarget"},
|
{7, nullptr, "SetDefaultTarget"},
|
||||||
{8, nullptr, "GetDefaultTarget"},
|
{8, nullptr, "GetDefaultTarget"},
|
||||||
{9, D<&IAudioController::GetAudioOutputMode>, "GetAudioOutputMode"},
|
{9, C<&IAudioController::GetAudioOutputMode>, "GetAudioOutputMode"},
|
||||||
{10, D<&IAudioController::SetAudioOutputMode>, "SetAudioOutputMode"},
|
{10, C<&IAudioController::SetAudioOutputMode>, "SetAudioOutputMode"},
|
||||||
{11, nullptr, "SetForceMutePolicy"},
|
{11, nullptr, "SetForceMutePolicy"},
|
||||||
{12, D<&IAudioController::GetForceMutePolicy>, "GetForceMutePolicy"},
|
{12, C<&IAudioController::GetForceMutePolicy>, "GetForceMutePolicy"},
|
||||||
{13, D<&IAudioController::GetOutputModeSetting>, "GetOutputModeSetting"},
|
{13, C<&IAudioController::GetOutputModeSetting>, "GetOutputModeSetting"},
|
||||||
{14, D<&IAudioController::SetOutputModeSetting>, "SetOutputModeSetting"},
|
{14, C<&IAudioController::SetOutputModeSetting>, "SetOutputModeSetting"},
|
||||||
{15, nullptr, "SetOutputTarget"},
|
{15, nullptr, "SetOutputTarget"},
|
||||||
{16, nullptr, "SetInputTargetForceEnabled"},
|
{16, nullptr, "SetInputTargetForceEnabled"},
|
||||||
{17, D<&IAudioController::SetHeadphoneOutputLevelMode>, "SetHeadphoneOutputLevelMode"},
|
{17, C<&IAudioController::SetHeadphoneOutputLevelMode>, "SetHeadphoneOutputLevelMode"},
|
||||||
{18, D<&IAudioController::GetHeadphoneOutputLevelMode>, "GetHeadphoneOutputLevelMode"},
|
{18, C<&IAudioController::GetHeadphoneOutputLevelMode>, "GetHeadphoneOutputLevelMode"},
|
||||||
{19, nullptr, "AcquireAudioVolumeUpdateEventForPlayReport"},
|
{19, nullptr, "AcquireAudioVolumeUpdateEventForPlayReport"},
|
||||||
{20, nullptr, "AcquireAudioOutputDeviceUpdateEventForPlayReport"},
|
{20, nullptr, "AcquireAudioOutputDeviceUpdateEventForPlayReport"},
|
||||||
{21, nullptr, "GetAudioOutputTargetForPlayReport"},
|
{21, nullptr, "GetAudioOutputTargetForPlayReport"},
|
||||||
{22, D<&IAudioController::NotifyHeadphoneVolumeWarningDisplayedEvent>, "NotifyHeadphoneVolumeWarningDisplayedEvent"},
|
{22, nullptr, "NotifyHeadphoneVolumeWarningDisplayedEvent"},
|
||||||
{23, nullptr, "SetSystemOutputMasterVolume"},
|
{23, nullptr, "SetSystemOutputMasterVolume"},
|
||||||
{24, nullptr, "GetSystemOutputMasterVolume"},
|
{24, nullptr, "GetSystemOutputMasterVolume"},
|
||||||
{25, nullptr, "GetAudioVolumeDataForPlayReport"},
|
{25, nullptr, "GetAudioVolumeDataForPlayReport"},
|
||||||
@ -44,11 +44,11 @@ IAudioController::IAudioController(Core::System& system_)
|
|||||||
{27, nullptr, "SetVolumeMappingTableForDev"},
|
{27, nullptr, "SetVolumeMappingTableForDev"},
|
||||||
{28, nullptr, "GetAudioOutputChannelCountForPlayReport"},
|
{28, nullptr, "GetAudioOutputChannelCountForPlayReport"},
|
||||||
{29, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"},
|
{29, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"},
|
||||||
{30, D<&IAudioController::SetSpeakerAutoMuteEnabled>, "SetSpeakerAutoMuteEnabled"},
|
{30, C<&IAudioController::SetSpeakerAutoMuteEnabled>, "SetSpeakerAutoMuteEnabled"},
|
||||||
{31, D<&IAudioController::IsSpeakerAutoMuteEnabled>, "IsSpeakerAutoMuteEnabled"},
|
{31, C<&IAudioController::IsSpeakerAutoMuteEnabled>, "IsSpeakerAutoMuteEnabled"},
|
||||||
{32, nullptr, "GetActiveOutputTarget"},
|
{32, nullptr, "GetActiveOutputTarget"},
|
||||||
{33, nullptr, "GetTargetDeviceInfo"},
|
{33, nullptr, "GetTargetDeviceInfo"},
|
||||||
{34, D<&IAudioController::AcquireTargetNotification>, "AcquireTargetNotification"},
|
{34, C<&IAudioController::AcquireTargetNotification>, "AcquireTargetNotification"},
|
||||||
{35, nullptr, "SetHearingProtectionSafeguardTimerRemainingTimeForDebug"},
|
{35, nullptr, "SetHearingProtectionSafeguardTimerRemainingTimeForDebug"},
|
||||||
{36, nullptr, "GetHearingProtectionSafeguardTimerRemainingTimeForDebug"},
|
{36, nullptr, "GetHearingProtectionSafeguardTimerRemainingTimeForDebug"},
|
||||||
{37, nullptr, "SetHearingProtectionSafeguardEnabled"},
|
{37, nullptr, "SetHearingProtectionSafeguardEnabled"},
|
||||||
@ -150,11 +150,6 @@ Result IAudioController::GetHeadphoneOutputLevelMode(
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IAudioController::NotifyHeadphoneVolumeWarningDisplayedEvent() {
|
|
||||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
|
||||||
R_SUCCEED();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result IAudioController::SetSpeakerAutoMuteEnabled(bool is_speaker_auto_mute_enabled) {
|
Result IAudioController::SetSpeakerAutoMuteEnabled(bool is_speaker_auto_mute_enabled) {
|
||||||
LOG_INFO(Audio, "called, is_speaker_auto_mute_enabled={}", is_speaker_auto_mute_enabled);
|
LOG_INFO(Audio, "called, is_speaker_auto_mute_enabled={}", is_speaker_auto_mute_enabled);
|
||||||
|
|
||||||
|
@ -45,7 +45,6 @@ private:
|
|||||||
Set::AudioOutputMode output_mode);
|
Set::AudioOutputMode output_mode);
|
||||||
Result SetHeadphoneOutputLevelMode(HeadphoneOutputLevelMode output_level_mode);
|
Result SetHeadphoneOutputLevelMode(HeadphoneOutputLevelMode output_level_mode);
|
||||||
Result GetHeadphoneOutputLevelMode(Out<HeadphoneOutputLevelMode> out_output_level_mode);
|
Result GetHeadphoneOutputLevelMode(Out<HeadphoneOutputLevelMode> out_output_level_mode);
|
||||||
Result NotifyHeadphoneVolumeWarningDisplayedEvent();
|
|
||||||
Result SetSpeakerAutoMuteEnabled(bool is_speaker_auto_mute_enabled);
|
Result SetSpeakerAutoMuteEnabled(bool is_speaker_auto_mute_enabled);
|
||||||
Result IsSpeakerAutoMuteEnabled(Out<bool> out_is_speaker_auto_mute_enabled);
|
Result IsSpeakerAutoMuteEnabled(Out<bool> out_is_speaker_auto_mute_enabled);
|
||||||
Result AcquireTargetNotification(OutCopyHandle<Kernel::KReadableEvent> out_notification_event);
|
Result AcquireTargetNotification(OutCopyHandle<Kernel::KReadableEvent> out_notification_event);
|
||||||
|
@ -1,163 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include "audio_core/audio_core.h"
|
|
||||||
#include "common/string_util.h"
|
|
||||||
#include "core/hle/service/audio/audio_device.h"
|
|
||||||
#include "core/hle/service/cmif_serialization.h"
|
|
||||||
|
|
||||||
namespace Service::Audio {
|
|
||||||
using namespace AudioCore::Renderer;
|
|
||||||
|
|
||||||
IAudioDevice::IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u32 revision,
|
|
||||||
u32 device_num)
|
|
||||||
: ServiceFramework{system_, "IAudioDevice"}, service_context{system_, "IAudioDevice"},
|
|
||||||
impl{std::make_unique<AudioDevice>(system_, applet_resource_user_id, revision)},
|
|
||||||
event{service_context.CreateEvent(fmt::format("IAudioDeviceEvent-{}", device_num))} {
|
|
||||||
static const FunctionInfo functions[] = {
|
|
||||||
{0, D<&IAudioDevice::ListAudioDeviceName>, "ListAudioDeviceName"},
|
|
||||||
{1, D<&IAudioDevice::SetAudioDeviceOutputVolume>, "SetAudioDeviceOutputVolume"},
|
|
||||||
{2, D<&IAudioDevice::GetAudioDeviceOutputVolume>, "GetAudioDeviceOutputVolume"},
|
|
||||||
{3, D<&IAudioDevice::GetActiveAudioDeviceName>, "GetActiveAudioDeviceName"},
|
|
||||||
{4, D<&IAudioDevice::QueryAudioDeviceSystemEvent>, "QueryAudioDeviceSystemEvent"},
|
|
||||||
{5, D<&IAudioDevice::GetActiveChannelCount>, "GetActiveChannelCount"},
|
|
||||||
{6, D<&IAudioDevice::ListAudioDeviceNameAuto>, "ListAudioDeviceNameAuto"},
|
|
||||||
{7, D<&IAudioDevice::SetAudioDeviceOutputVolumeAuto>, "SetAudioDeviceOutputVolumeAuto"},
|
|
||||||
{8, D<&IAudioDevice::GetAudioDeviceOutputVolumeAuto>, "GetAudioDeviceOutputVolumeAuto"},
|
|
||||||
{10, D<&IAudioDevice::GetActiveAudioDeviceNameAuto>, "GetActiveAudioDeviceNameAuto"},
|
|
||||||
{11, D<&IAudioDevice::QueryAudioDeviceInputEvent>, "QueryAudioDeviceInputEvent"},
|
|
||||||
{12, D<&IAudioDevice::QueryAudioDeviceOutputEvent>, "QueryAudioDeviceOutputEvent"},
|
|
||||||
{13, D<&IAudioDevice::GetActiveAudioDeviceName>, "GetActiveAudioOutputDeviceName"},
|
|
||||||
{14, D<&IAudioDevice::ListAudioOutputDeviceName>, "ListAudioOutputDeviceName"},
|
|
||||||
};
|
|
||||||
RegisterHandlers(functions);
|
|
||||||
|
|
||||||
event->Signal();
|
|
||||||
}
|
|
||||||
|
|
||||||
IAudioDevice::~IAudioDevice() {
|
|
||||||
service_context.CloseEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result IAudioDevice::ListAudioDeviceName(
|
|
||||||
OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_names, Out<s32> out_count) {
|
|
||||||
R_RETURN(this->ListAudioDeviceNameAuto(out_names, out_count));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result IAudioDevice::SetAudioDeviceOutputVolume(
|
|
||||||
InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> name, f32 volume) {
|
|
||||||
R_RETURN(this->SetAudioDeviceOutputVolumeAuto(name, volume));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result IAudioDevice::GetAudioDeviceOutputVolume(
|
|
||||||
Out<f32> out_volume, InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> name) {
|
|
||||||
R_RETURN(this->GetAudioDeviceOutputVolumeAuto(out_volume, name));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result IAudioDevice::GetActiveAudioDeviceName(
|
|
||||||
OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_name) {
|
|
||||||
R_RETURN(this->GetActiveAudioDeviceNameAuto(out_name));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result IAudioDevice::ListAudioDeviceNameAuto(
|
|
||||||
OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> out_names,
|
|
||||||
Out<s32> out_count) {
|
|
||||||
*out_count = impl->ListAudioDeviceName(out_names);
|
|
||||||
|
|
||||||
std::string out{};
|
|
||||||
for (s32 i = 0; i < *out_count; i++) {
|
|
||||||
std::string a{};
|
|
||||||
u32 j = 0;
|
|
||||||
while (out_names[i].name[j] != '\0') {
|
|
||||||
a += out_names[i].name[j];
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
out += "\n\t" + a;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_DEBUG(Service_Audio, "called.\nNames={}", out);
|
|
||||||
R_SUCCEED();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result IAudioDevice::SetAudioDeviceOutputVolumeAuto(
|
|
||||||
InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> name, f32 volume) {
|
|
||||||
R_UNLESS(!name.empty(), Audio::ResultInsufficientBuffer);
|
|
||||||
|
|
||||||
const std::string device_name = Common::StringFromBuffer(name[0].name);
|
|
||||||
LOG_DEBUG(Service_Audio, "called. name={}, volume={}", device_name, volume);
|
|
||||||
|
|
||||||
if (device_name == "AudioTvOutput") {
|
|
||||||
impl->SetDeviceVolumes(volume);
|
|
||||||
}
|
|
||||||
|
|
||||||
R_SUCCEED();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result IAudioDevice::GetAudioDeviceOutputVolumeAuto(
|
|
||||||
Out<f32> out_volume, InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> name) {
|
|
||||||
R_UNLESS(!name.empty(), Audio::ResultInsufficientBuffer);
|
|
||||||
|
|
||||||
const std::string device_name = Common::StringFromBuffer(name[0].name);
|
|
||||||
LOG_DEBUG(Service_Audio, "called. Name={}", device_name);
|
|
||||||
|
|
||||||
*out_volume = 1.0f;
|
|
||||||
if (device_name == "AudioTvOutput") {
|
|
||||||
*out_volume = impl->GetDeviceVolume(device_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
R_SUCCEED();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result IAudioDevice::GetActiveAudioDeviceNameAuto(
|
|
||||||
OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> out_name) {
|
|
||||||
R_UNLESS(!out_name.empty(), Audio::ResultInsufficientBuffer);
|
|
||||||
out_name[0] = AudioDevice::AudioDeviceName("AudioTvOutput");
|
|
||||||
LOG_DEBUG(Service_Audio, "(STUBBED) called");
|
|
||||||
R_SUCCEED();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result IAudioDevice::QueryAudioDeviceSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
|
|
||||||
LOG_DEBUG(Service_Audio, "(STUBBED) called");
|
|
||||||
event->Signal();
|
|
||||||
*out_event = &event->GetReadableEvent();
|
|
||||||
R_SUCCEED();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result IAudioDevice::QueryAudioDeviceInputEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
|
|
||||||
LOG_DEBUG(Service_Audio, "(STUBBED) called");
|
|
||||||
*out_event = &event->GetReadableEvent();
|
|
||||||
R_SUCCEED();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result IAudioDevice::QueryAudioDeviceOutputEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
|
|
||||||
LOG_DEBUG(Service_Audio, "called");
|
|
||||||
*out_event = &event->GetReadableEvent();
|
|
||||||
R_SUCCEED();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result IAudioDevice::GetActiveChannelCount(Out<u32> out_active_channel_count) {
|
|
||||||
*out_active_channel_count = system.AudioCore().GetOutputSink().GetSystemChannels();
|
|
||||||
LOG_DEBUG(Service_Audio, "(STUBBED) called. Channels={}", *out_active_channel_count);
|
|
||||||
R_SUCCEED();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result IAudioDevice::ListAudioOutputDeviceName(
|
|
||||||
OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_names, Out<s32> out_count) {
|
|
||||||
*out_count = impl->ListAudioOutputDeviceName(out_names);
|
|
||||||
|
|
||||||
std::string out{};
|
|
||||||
for (s32 i = 0; i < *out_count; i++) {
|
|
||||||
std::string a{};
|
|
||||||
u32 j = 0;
|
|
||||||
while (out_names[i].name[j] != '\0') {
|
|
||||||
a += out_names[i].name[j];
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
out += "\n\t" + a;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_DEBUG(Service_Audio, "called.\nNames={}", out);
|
|
||||||
R_SUCCEED();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Service::Audio
|
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user