Compare commits
6 Commits
android-17
...
android-16
Author | SHA1 | Date | |
---|---|---|---|
13c8e32be6 | |||
ab6d23b372 | |||
ec17af19af | |||
9057489024 | |||
ae5656a729 | |||
c2873b00a2 |
@ -6,12 +6,7 @@
|
|||||||
export NDK_CCACHE="$(which ccache)"
|
export NDK_CCACHE="$(which ccache)"
|
||||||
ccache -s
|
ccache -s
|
||||||
|
|
||||||
BUILD_FLAVOR="mainline"
|
BUILD_FLAVOR=mainline
|
||||||
|
|
||||||
BUILD_TYPE="release"
|
|
||||||
if [ "${GITHUB_REPOSITORY}" == "yuzu-emu/yuzu" ]; then
|
|
||||||
BUILD_TYPE="relWithDebInfo"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -z "${ANDROID_KEYSTORE_B64}" ]; then
|
if [ ! -z "${ANDROID_KEYSTORE_B64}" ]; then
|
||||||
export ANDROID_KEYSTORE_FILE="${GITHUB_WORKSPACE}/ks.jks"
|
export ANDROID_KEYSTORE_FILE="${GITHUB_WORKSPACE}/ks.jks"
|
||||||
@ -20,7 +15,7 @@ fi
|
|||||||
|
|
||||||
cd src/android
|
cd src/android
|
||||||
chmod +x ./gradlew
|
chmod +x ./gradlew
|
||||||
./gradlew "assemble${BUILD_FLAVOR}${BUILD_TYPE}" "bundle${BUILD_FLAVOR}${BUILD_TYPE}"
|
./gradlew "assemble${BUILD_FLAVOR}Release" "bundle${BUILD_FLAVOR}Release"
|
||||||
|
|
||||||
ccache -s
|
ccache -s
|
||||||
|
|
||||||
|
@ -7,16 +7,9 @@
|
|||||||
|
|
||||||
REV_NAME="yuzu-${GITDATE}-${GITREV}"
|
REV_NAME="yuzu-${GITDATE}-${GITREV}"
|
||||||
|
|
||||||
BUILD_FLAVOR="mainline"
|
BUILD_FLAVOR=mainline
|
||||||
|
|
||||||
BUILD_TYPE_LOWER="release"
|
cp src/android/app/build/outputs/apk/"${BUILD_FLAVOR}/release/app-${BUILD_FLAVOR}-release.apk" \
|
||||||
BUILD_TYPE_UPPER="Release"
|
|
||||||
if [ "${GITHUB_REPOSITORY}" == "yuzu-emu/yuzu" ]; then
|
|
||||||
BUILD_TYPE_LOWER="relWithDebInfo"
|
|
||||||
BUILD_TYPE_UPPER="RelWithDebInfo"
|
|
||||||
fi
|
|
||||||
|
|
||||||
cp src/android/app/build/outputs/apk/"${BUILD_FLAVOR}/${BUILD_TYPE_LOWER}/app-${BUILD_FLAVOR}-${BUILD_TYPE_LOWER}.apk" \
|
|
||||||
"artifacts/${REV_NAME}.apk"
|
"artifacts/${REV_NAME}.apk"
|
||||||
cp src/android/app/build/outputs/bundle/"${BUILD_FLAVOR}${BUILD_TYPE_UPPER}"/"app-${BUILD_FLAVOR}-${BUILD_TYPE_LOWER}.aab" \
|
cp src/android/app/build/outputs/bundle/"${BUILD_FLAVOR}Release"/"app-${BUILD_FLAVOR}-release.aab" \
|
||||||
"artifacts/${REV_NAME}.aab"
|
"artifacts/${REV_NAME}.aab"
|
||||||
|
@ -305,7 +305,7 @@ find_package(ZLIB 1.2 REQUIRED)
|
|||||||
find_package(zstd 1.5 REQUIRED)
|
find_package(zstd 1.5 REQUIRED)
|
||||||
|
|
||||||
if (NOT YUZU_USE_EXTERNAL_VULKAN_HEADERS)
|
if (NOT YUZU_USE_EXTERNAL_VULKAN_HEADERS)
|
||||||
find_package(Vulkan 1.3.274 REQUIRED)
|
find_package(Vulkan 1.3.256 REQUIRED)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ENABLE_LIBUSB)
|
if (ENABLE_LIBUSB)
|
||||||
|
10
README.md
10
README.md
@ -1,10 +1,10 @@
|
|||||||
| Pull Request | Commit | Title | Author | Merged? |
|
| Pull Request | Commit | Title | Author | Merged? |
|
||||||
|----|----|----|----|----|
|
|----|----|----|----|----|
|
||||||
| [12454](https://github.com/yuzu-emu/yuzu//pull/12454) | [`3a4e7d45f`](https://github.com/yuzu-emu/yuzu//pull/12454/files) | core_timing: minor refactors | [liamwhite](https://github.com/liamwhite/) | Yes |
|
| [12304](https://github.com/yuzu-emu/yuzu//pull/12304) | [`fcc85abe2`](https://github.com/yuzu-emu/yuzu//pull/12304/files) | nvnflinger: mark buffer as acquired when acquired | [liamwhite](https://github.com/liamwhite/) | Yes |
|
||||||
| [12466](https://github.com/yuzu-emu/yuzu//pull/12466) | [`adb2af0a2`](https://github.com/yuzu-emu/yuzu//pull/12466/files) | core: track separate heap allocation for linux | [liamwhite](https://github.com/liamwhite/) | Yes |
|
| [12349](https://github.com/yuzu-emu/yuzu//pull/12349) | [`6851e9329`](https://github.com/yuzu-emu/yuzu//pull/12349/files) | Have GetActiveChannelCount return the system channels instead of host device channels | [Kelebek1](https://github.com/Kelebek1/) | Yes |
|
||||||
| [12501](https://github.com/yuzu-emu/yuzu//pull/12501) | [`d1c99c5d5`](https://github.com/yuzu-emu/yuzu//pull/12501/files) | ips_layer: prevent out of bounds access with offset exceeding module size | [liamwhite](https://github.com/liamwhite/) | Yes |
|
| [12382](https://github.com/yuzu-emu/yuzu//pull/12382) | [`7fc06260d`](https://github.com/yuzu-emu/yuzu//pull/12382/files) | renderer_vulkan: allow up to 7 swapchain images | [liamwhite](https://github.com/liamwhite/) | Yes |
|
||||||
| [12513](https://github.com/yuzu-emu/yuzu//pull/12513) | [`558192abf`](https://github.com/yuzu-emu/yuzu//pull/12513/files) | jit: use code memory handles correctly | [liamwhite](https://github.com/liamwhite/) | Yes |
|
| [12387](https://github.com/yuzu-emu/yuzu//pull/12387) | [`6ca530a72`](https://github.com/yuzu-emu/yuzu//pull/12387/files) | android: add oboe audio sink | [liamwhite](https://github.com/liamwhite/) | Yes |
|
||||||
| [12518](https://github.com/yuzu-emu/yuzu//pull/12518) | [`aa4d15594`](https://github.com/yuzu-emu/yuzu//pull/12518/files) | android: Migrate remaining settings to ini | [t895](https://github.com/t895/) | Yes |
|
| [12391](https://github.com/yuzu-emu/yuzu//pull/12391) | [`65e646eeb`](https://github.com/yuzu-emu/yuzu//pull/12391/files) | Revert "video_core: use interval map for page count tracking" | [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.
|
||||||
|
2
externals/Vulkan-Headers
vendored
2
externals/Vulkan-Headers
vendored
Submodule externals/Vulkan-Headers updated: 80207f9da8...df60f03168
@ -10,7 +10,7 @@ plugins {
|
|||||||
id("com.android.application")
|
id("com.android.application")
|
||||||
id("org.jetbrains.kotlin.android")
|
id("org.jetbrains.kotlin.android")
|
||||||
id("kotlin-parcelize")
|
id("kotlin-parcelize")
|
||||||
kotlin("plugin.serialization") version "1.9.20"
|
kotlin("plugin.serialization") version "1.8.21"
|
||||||
id("androidx.navigation.safeargs.kotlin")
|
id("androidx.navigation.safeargs.kotlin")
|
||||||
id("org.jlleitschuh.gradle.ktlint") version "11.4.0"
|
id("org.jlleitschuh.gradle.ktlint") version "11.4.0"
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,6 @@ import org.yuzu.yuzu_emu.utils.ForegroundService
|
|||||||
import org.yuzu.yuzu_emu.utils.InputHandler
|
import org.yuzu.yuzu_emu.utils.InputHandler
|
||||||
import org.yuzu.yuzu_emu.utils.Log
|
import org.yuzu.yuzu_emu.utils.Log
|
||||||
import org.yuzu.yuzu_emu.utils.MemoryUtil
|
import org.yuzu.yuzu_emu.utils.MemoryUtil
|
||||||
import org.yuzu.yuzu_emu.utils.NativeConfig
|
|
||||||
import org.yuzu.yuzu_emu.utils.NfcReader
|
import org.yuzu.yuzu_emu.utils.NfcReader
|
||||||
import org.yuzu.yuzu_emu.utils.ThemeHelper
|
import org.yuzu.yuzu_emu.utils.ThemeHelper
|
||||||
import java.text.NumberFormat
|
import java.text.NumberFormat
|
||||||
@ -171,11 +170,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
|||||||
stopMotionSensorListener()
|
stopMotionSensorListener()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStop() {
|
|
||||||
super.onStop()
|
|
||||||
NativeConfig.saveGlobalConfig()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onUserLeaveHint() {
|
override fun onUserLeaveHint() {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
|
||||||
if (BooleanSetting.PICTURE_IN_PICTURE.getBoolean() && !isInPictureInPictureMode) {
|
if (BooleanSetting.PICTURE_IN_PICTURE.getBoolean() && !isInPictureInPictureMode) {
|
||||||
|
@ -18,14 +18,7 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
|
|||||||
RENDERER_REACTIVE_FLUSHING("use_reactive_flushing"),
|
RENDERER_REACTIVE_FLUSHING("use_reactive_flushing"),
|
||||||
RENDERER_DEBUG("debug"),
|
RENDERER_DEBUG("debug"),
|
||||||
PICTURE_IN_PICTURE("picture_in_picture"),
|
PICTURE_IN_PICTURE("picture_in_picture"),
|
||||||
USE_CUSTOM_RTC("custom_rtc_enabled"),
|
USE_CUSTOM_RTC("custom_rtc_enabled");
|
||||||
BLACK_BACKGROUNDS("black_backgrounds"),
|
|
||||||
JOYSTICK_REL_CENTER("joystick_rel_center"),
|
|
||||||
DPAD_SLIDE("dpad_slide"),
|
|
||||||
HAPTIC_FEEDBACK("haptic_feedback"),
|
|
||||||
SHOW_PERFORMANCE_OVERLAY("show_performance_overlay"),
|
|
||||||
SHOW_INPUT_OVERLAY("show_input_overlay"),
|
|
||||||
TOUCHSCREEN("touchscreen");
|
|
||||||
|
|
||||||
override fun getBoolean(needsGlobal: Boolean): Boolean =
|
override fun getBoolean(needsGlobal: Boolean): Boolean =
|
||||||
NativeConfig.getBoolean(key, needsGlobal)
|
NativeConfig.getBoolean(key, needsGlobal)
|
||||||
|
@ -18,12 +18,7 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
|
|||||||
RENDERER_ANTI_ALIASING("anti_aliasing"),
|
RENDERER_ANTI_ALIASING("anti_aliasing"),
|
||||||
RENDERER_SCREEN_LAYOUT("screen_layout"),
|
RENDERER_SCREEN_LAYOUT("screen_layout"),
|
||||||
RENDERER_ASPECT_RATIO("aspect_ratio"),
|
RENDERER_ASPECT_RATIO("aspect_ratio"),
|
||||||
AUDIO_OUTPUT_ENGINE("output_engine"),
|
AUDIO_OUTPUT_ENGINE("output_engine");
|
||||||
MAX_ANISOTROPY("max_anisotropy"),
|
|
||||||
THEME("theme"),
|
|
||||||
THEME_MODE("theme_mode"),
|
|
||||||
OVERLAY_SCALE("control_scale"),
|
|
||||||
OVERLAY_OPACITY("control_opacity");
|
|
||||||
|
|
||||||
override fun getInt(needsGlobal: Boolean): Int = NativeConfig.getInt(key, needsGlobal)
|
override fun getInt(needsGlobal: Boolean): Int = NativeConfig.getInt(key, needsGlobal)
|
||||||
|
|
||||||
|
@ -15,10 +15,18 @@ object Settings {
|
|||||||
SECTION_DEBUG(R.string.preferences_debug);
|
SECTION_DEBUG(R.string.preferences_debug);
|
||||||
}
|
}
|
||||||
|
|
||||||
const val PREF_FIRST_APP_LAUNCH = "FirstApplicationLaunch"
|
|
||||||
const val PREF_MEMORY_WARNING_SHOWN = "MemoryWarningShown"
|
const val PREF_MEMORY_WARNING_SHOWN = "MemoryWarningShown"
|
||||||
|
|
||||||
// Deprecated input overlay preference keys
|
const val PREF_OVERLAY_VERSION = "OverlayVersion"
|
||||||
|
const val PREF_LANDSCAPE_OVERLAY_VERSION = "LandscapeOverlayVersion"
|
||||||
|
const val PREF_PORTRAIT_OVERLAY_VERSION = "PortraitOverlayVersion"
|
||||||
|
const val PREF_FOLDABLE_OVERLAY_VERSION = "FoldableOverlayVersion"
|
||||||
|
val overlayLayoutPrefs = listOf(
|
||||||
|
PREF_LANDSCAPE_OVERLAY_VERSION,
|
||||||
|
PREF_PORTRAIT_OVERLAY_VERSION,
|
||||||
|
PREF_FOLDABLE_OVERLAY_VERSION
|
||||||
|
)
|
||||||
|
|
||||||
const val PREF_CONTROL_SCALE = "controlScale"
|
const val PREF_CONTROL_SCALE = "controlScale"
|
||||||
const val PREF_CONTROL_OPACITY = "controlOpacity"
|
const val PREF_CONTROL_OPACITY = "controlOpacity"
|
||||||
const val PREF_TOUCH_ENABLED = "isTouchEnabled"
|
const val PREF_TOUCH_ENABLED = "isTouchEnabled"
|
||||||
@ -39,12 +47,23 @@ object Settings {
|
|||||||
const val PREF_BUTTON_STICK_R = "buttonToggle14"
|
const val PREF_BUTTON_STICK_R = "buttonToggle14"
|
||||||
const val PREF_BUTTON_HOME = "buttonToggle15"
|
const val PREF_BUTTON_HOME = "buttonToggle15"
|
||||||
const val PREF_BUTTON_SCREENSHOT = "buttonToggle16"
|
const val PREF_BUTTON_SCREENSHOT = "buttonToggle16"
|
||||||
|
|
||||||
const val PREF_MENU_SETTINGS_JOYSTICK_REL_CENTER = "EmulationMenuSettings_JoystickRelCenter"
|
const val PREF_MENU_SETTINGS_JOYSTICK_REL_CENTER = "EmulationMenuSettings_JoystickRelCenter"
|
||||||
const val PREF_MENU_SETTINGS_DPAD_SLIDE = "EmulationMenuSettings_DpadSlideEnable"
|
const val PREF_MENU_SETTINGS_DPAD_SLIDE = "EmulationMenuSettings_DpadSlideEnable"
|
||||||
const val PREF_MENU_SETTINGS_HAPTICS = "EmulationMenuSettings_Haptics"
|
const val PREF_MENU_SETTINGS_HAPTICS = "EmulationMenuSettings_Haptics"
|
||||||
const val PREF_MENU_SETTINGS_SHOW_FPS = "EmulationMenuSettings_ShowFps"
|
const val PREF_MENU_SETTINGS_SHOW_FPS = "EmulationMenuSettings_ShowFps"
|
||||||
const val PREF_MENU_SETTINGS_SHOW_OVERLAY = "EmulationMenuSettings_ShowOverlay"
|
const val PREF_MENU_SETTINGS_SHOW_OVERLAY = "EmulationMenuSettings_ShowOverlay"
|
||||||
|
|
||||||
|
const val PREF_FIRST_APP_LAUNCH = "FirstApplicationLaunch"
|
||||||
|
const val PREF_THEME = "Theme"
|
||||||
|
const val PREF_THEME_MODE = "ThemeMode"
|
||||||
|
const val PREF_BLACK_BACKGROUNDS = "BlackBackgrounds"
|
||||||
|
|
||||||
val overlayPreferences = listOf(
|
val overlayPreferences = listOf(
|
||||||
|
PREF_OVERLAY_VERSION,
|
||||||
|
PREF_CONTROL_SCALE,
|
||||||
|
PREF_CONTROL_OPACITY,
|
||||||
|
PREF_TOUCH_ENABLED,
|
||||||
PREF_BUTTON_A,
|
PREF_BUTTON_A,
|
||||||
PREF_BUTTON_B,
|
PREF_BUTTON_B,
|
||||||
PREF_BUTTON_X,
|
PREF_BUTTON_X,
|
||||||
@ -64,21 +83,6 @@ object Settings {
|
|||||||
PREF_BUTTON_STICK_R
|
PREF_BUTTON_STICK_R
|
||||||
)
|
)
|
||||||
|
|
||||||
// Deprecated layout preference keys
|
|
||||||
const val PREF_LANDSCAPE_SUFFIX = "_Landscape"
|
|
||||||
const val PREF_PORTRAIT_SUFFIX = "_Portrait"
|
|
||||||
const val PREF_FOLDABLE_SUFFIX = "_Foldable"
|
|
||||||
val overlayLayoutSuffixes = listOf(
|
|
||||||
PREF_LANDSCAPE_SUFFIX,
|
|
||||||
PREF_PORTRAIT_SUFFIX,
|
|
||||||
PREF_FOLDABLE_SUFFIX
|
|
||||||
)
|
|
||||||
|
|
||||||
// Deprecated theme preference keys
|
|
||||||
const val PREF_THEME = "Theme"
|
|
||||||
const val PREF_THEME_MODE = "ThemeMode"
|
|
||||||
const val PREF_BLACK_BACKGROUNDS = "BlackBackgrounds"
|
|
||||||
|
|
||||||
const val LayoutOption_Unspecified = 0
|
const val LayoutOption_Unspecified = 0
|
||||||
const val LayoutOption_MobilePortrait = 4
|
const val LayoutOption_MobilePortrait = 4
|
||||||
const val LayoutOption_MobileLandscape = 5
|
const val LayoutOption_MobileLandscape = 5
|
||||||
|
@ -243,15 +243,6 @@ abstract class SettingsItem(
|
|||||||
R.string.renderer_reactive_flushing_description
|
R.string.renderer_reactive_flushing_description
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
put(
|
|
||||||
SingleChoiceSetting(
|
|
||||||
IntSetting.MAX_ANISOTROPY,
|
|
||||||
R.string.anisotropic_filtering,
|
|
||||||
R.string.anisotropic_filtering_description,
|
|
||||||
R.array.anisoEntries,
|
|
||||||
R.array.anisoValues
|
|
||||||
)
|
|
||||||
)
|
|
||||||
put(
|
put(
|
||||||
SingleChoiceSetting(
|
SingleChoiceSetting(
|
||||||
IntSetting.AUDIO_OUTPUT_ENGINE,
|
IntSetting.AUDIO_OUTPUT_ENGINE,
|
||||||
@ -307,7 +298,6 @@ abstract class SettingsItem(
|
|||||||
|
|
||||||
override val key: String = FASTMEM_COMBINED
|
override val key: String = FASTMEM_COMBINED
|
||||||
override val isRuntimeModifiable: Boolean = false
|
override val isRuntimeModifiable: Boolean = false
|
||||||
override val pairedSettingKey = BooleanSetting.CPU_DEBUG_MODE.key
|
|
||||||
override val defaultValue: Boolean = true
|
override val defaultValue: Boolean = true
|
||||||
override val isSwitchable: Boolean = true
|
override val isSwitchable: Boolean = true
|
||||||
override var global: Boolean
|
override var global: Boolean
|
||||||
|
@ -3,8 +3,10 @@
|
|||||||
|
|
||||||
package org.yuzu.yuzu_emu.features.settings.ui
|
package org.yuzu.yuzu_emu.features.settings.ui
|
||||||
|
|
||||||
|
import android.content.SharedPreferences
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
import org.yuzu.yuzu_emu.NativeLibrary
|
import org.yuzu.yuzu_emu.NativeLibrary
|
||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
import org.yuzu.yuzu_emu.YuzuApplication
|
import org.yuzu.yuzu_emu.YuzuApplication
|
||||||
@ -27,6 +29,9 @@ class SettingsFragmentPresenter(
|
|||||||
) {
|
) {
|
||||||
private var settingsList = ArrayList<SettingsItem>()
|
private var settingsList = ArrayList<SettingsItem>()
|
||||||
|
|
||||||
|
private val preferences: SharedPreferences
|
||||||
|
get() = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
|
||||||
|
|
||||||
// Extension for altering settings list based on each setting's properties
|
// Extension for altering settings list based on each setting's properties
|
||||||
fun ArrayList<SettingsItem>.add(key: String) {
|
fun ArrayList<SettingsItem>.add(key: String) {
|
||||||
val item = SettingsItem.settingsItems[key]!!
|
val item = SettingsItem.settingsItems[key]!!
|
||||||
@ -144,7 +149,6 @@ class SettingsFragmentPresenter(
|
|||||||
add(IntSetting.RENDERER_VSYNC.key)
|
add(IntSetting.RENDERER_VSYNC.key)
|
||||||
add(IntSetting.RENDERER_SCALING_FILTER.key)
|
add(IntSetting.RENDERER_SCALING_FILTER.key)
|
||||||
add(IntSetting.RENDERER_ANTI_ALIASING.key)
|
add(IntSetting.RENDERER_ANTI_ALIASING.key)
|
||||||
add(IntSetting.MAX_ANISOTROPY.key)
|
|
||||||
add(IntSetting.RENDERER_SCREEN_LAYOUT.key)
|
add(IntSetting.RENDERER_SCREEN_LAYOUT.key)
|
||||||
add(IntSetting.RENDERER_ASPECT_RATIO.key)
|
add(IntSetting.RENDERER_ASPECT_RATIO.key)
|
||||||
add(BooleanSetting.PICTURE_IN_PICTURE.key)
|
add(BooleanSetting.PICTURE_IN_PICTURE.key)
|
||||||
@ -165,19 +169,25 @@ class SettingsFragmentPresenter(
|
|||||||
private fun addThemeSettings(sl: ArrayList<SettingsItem>) {
|
private fun addThemeSettings(sl: ArrayList<SettingsItem>) {
|
||||||
sl.apply {
|
sl.apply {
|
||||||
val theme: AbstractIntSetting = object : AbstractIntSetting {
|
val theme: AbstractIntSetting = object : AbstractIntSetting {
|
||||||
override fun getInt(needsGlobal: Boolean): Int = IntSetting.THEME.getInt()
|
override fun getInt(needsGlobal: Boolean): Int =
|
||||||
|
preferences.getInt(Settings.PREF_THEME, 0)
|
||||||
|
|
||||||
override fun setInt(value: Int) {
|
override fun setInt(value: Int) {
|
||||||
IntSetting.THEME.setInt(value)
|
preferences.edit()
|
||||||
|
.putInt(Settings.PREF_THEME, value)
|
||||||
|
.apply()
|
||||||
settingsViewModel.setShouldRecreate(true)
|
settingsViewModel.setShouldRecreate(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val key: String = IntSetting.THEME.key
|
override val key: String = Settings.PREF_THEME
|
||||||
override val isRuntimeModifiable: Boolean = IntSetting.THEME.isRuntimeModifiable
|
override val isRuntimeModifiable: Boolean = false
|
||||||
override fun getValueAsString(needsGlobal: Boolean): String =
|
override fun getValueAsString(needsGlobal: Boolean): String = getInt().toString()
|
||||||
IntSetting.THEME.getValueAsString()
|
override val defaultValue: Int = 0
|
||||||
|
override fun reset() {
|
||||||
override val defaultValue: Int = IntSetting.THEME.defaultValue
|
preferences.edit()
|
||||||
override fun reset() = IntSetting.THEME.setInt(defaultValue)
|
.putInt(Settings.PREF_THEME, defaultValue)
|
||||||
|
.apply()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
@ -203,22 +213,24 @@ class SettingsFragmentPresenter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val themeMode: AbstractIntSetting = object : AbstractIntSetting {
|
val themeMode: AbstractIntSetting = object : AbstractIntSetting {
|
||||||
override fun getInt(needsGlobal: Boolean): Int = IntSetting.THEME_MODE.getInt()
|
override fun getInt(needsGlobal: Boolean): Int =
|
||||||
|
preferences.getInt(Settings.PREF_THEME_MODE, -1)
|
||||||
|
|
||||||
override fun setInt(value: Int) {
|
override fun setInt(value: Int) {
|
||||||
IntSetting.THEME_MODE.setInt(value)
|
preferences.edit()
|
||||||
|
.putInt(Settings.PREF_THEME_MODE, value)
|
||||||
|
.apply()
|
||||||
settingsViewModel.setShouldRecreate(true)
|
settingsViewModel.setShouldRecreate(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val key: String = IntSetting.THEME_MODE.key
|
override val key: String = Settings.PREF_THEME_MODE
|
||||||
override val isRuntimeModifiable: Boolean =
|
override val isRuntimeModifiable: Boolean = false
|
||||||
IntSetting.THEME_MODE.isRuntimeModifiable
|
override fun getValueAsString(needsGlobal: Boolean): String = getInt().toString()
|
||||||
|
override val defaultValue: Int = -1
|
||||||
override fun getValueAsString(needsGlobal: Boolean): String =
|
|
||||||
IntSetting.THEME_MODE.getValueAsString()
|
|
||||||
|
|
||||||
override val defaultValue: Int = IntSetting.THEME_MODE.defaultValue
|
|
||||||
override fun reset() {
|
override fun reset() {
|
||||||
IntSetting.THEME_MODE.setInt(defaultValue)
|
preferences.edit()
|
||||||
|
.putInt(Settings.PREF_BLACK_BACKGROUNDS, defaultValue)
|
||||||
|
.apply()
|
||||||
settingsViewModel.setShouldRecreate(true)
|
settingsViewModel.setShouldRecreate(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -235,24 +247,25 @@ class SettingsFragmentPresenter(
|
|||||||
|
|
||||||
val blackBackgrounds: AbstractBooleanSetting = object : AbstractBooleanSetting {
|
val blackBackgrounds: AbstractBooleanSetting = object : AbstractBooleanSetting {
|
||||||
override fun getBoolean(needsGlobal: Boolean): Boolean =
|
override fun getBoolean(needsGlobal: Boolean): Boolean =
|
||||||
BooleanSetting.BLACK_BACKGROUNDS.getBoolean()
|
preferences.getBoolean(Settings.PREF_BLACK_BACKGROUNDS, false)
|
||||||
|
|
||||||
override fun setBoolean(value: Boolean) {
|
override fun setBoolean(value: Boolean) {
|
||||||
BooleanSetting.BLACK_BACKGROUNDS.setBoolean(value)
|
preferences.edit()
|
||||||
|
.putBoolean(Settings.PREF_BLACK_BACKGROUNDS, value)
|
||||||
|
.apply()
|
||||||
settingsViewModel.setShouldRecreate(true)
|
settingsViewModel.setShouldRecreate(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val key: String = BooleanSetting.BLACK_BACKGROUNDS.key
|
override val key: String = Settings.PREF_BLACK_BACKGROUNDS
|
||||||
override val isRuntimeModifiable: Boolean =
|
override val isRuntimeModifiable: Boolean = false
|
||||||
BooleanSetting.BLACK_BACKGROUNDS.isRuntimeModifiable
|
|
||||||
|
|
||||||
override fun getValueAsString(needsGlobal: Boolean): String =
|
override fun getValueAsString(needsGlobal: Boolean): String =
|
||||||
BooleanSetting.BLACK_BACKGROUNDS.getValueAsString()
|
getBoolean().toString()
|
||||||
|
|
||||||
override val defaultValue: Boolean = BooleanSetting.BLACK_BACKGROUNDS.defaultValue
|
override val defaultValue: Boolean = false
|
||||||
override fun reset() {
|
override fun reset() {
|
||||||
BooleanSetting.BLACK_BACKGROUNDS
|
preferences.edit()
|
||||||
.setBoolean(BooleanSetting.BLACK_BACKGROUNDS.defaultValue)
|
.putBoolean(Settings.PREF_BLACK_BACKGROUNDS, defaultValue)
|
||||||
|
.apply()
|
||||||
settingsViewModel.setShouldRecreate(true)
|
settingsViewModel.setShouldRecreate(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import android.annotation.SuppressLint
|
|||||||
import android.app.AlertDialog
|
import android.app.AlertDialog
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
|
import android.content.SharedPreferences
|
||||||
import android.content.pm.ActivityInfo
|
import android.content.pm.ActivityInfo
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
@ -32,6 +33,7 @@ import androidx.lifecycle.lifecycleScope
|
|||||||
import androidx.lifecycle.repeatOnLifecycle
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
import androidx.navigation.findNavController
|
import androidx.navigation.findNavController
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
import androidx.window.layout.FoldingFeature
|
import androidx.window.layout.FoldingFeature
|
||||||
import androidx.window.layout.WindowInfoTracker
|
import androidx.window.layout.WindowInfoTracker
|
||||||
import androidx.window.layout.WindowLayoutInfo
|
import androidx.window.layout.WindowLayoutInfo
|
||||||
@ -44,22 +46,22 @@ import kotlinx.coroutines.launch
|
|||||||
import org.yuzu.yuzu_emu.HomeNavigationDirections
|
import org.yuzu.yuzu_emu.HomeNavigationDirections
|
||||||
import org.yuzu.yuzu_emu.NativeLibrary
|
import org.yuzu.yuzu_emu.NativeLibrary
|
||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
|
import org.yuzu.yuzu_emu.YuzuApplication
|
||||||
import org.yuzu.yuzu_emu.activities.EmulationActivity
|
import org.yuzu.yuzu_emu.activities.EmulationActivity
|
||||||
import org.yuzu.yuzu_emu.databinding.DialogOverlayAdjustBinding
|
import org.yuzu.yuzu_emu.databinding.DialogOverlayAdjustBinding
|
||||||
import org.yuzu.yuzu_emu.databinding.FragmentEmulationBinding
|
import org.yuzu.yuzu_emu.databinding.FragmentEmulationBinding
|
||||||
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.features.settings.model.Settings
|
import org.yuzu.yuzu_emu.features.settings.model.Settings
|
||||||
import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
|
import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
|
||||||
import org.yuzu.yuzu_emu.model.DriverViewModel
|
import org.yuzu.yuzu_emu.model.DriverViewModel
|
||||||
import org.yuzu.yuzu_emu.model.Game
|
import org.yuzu.yuzu_emu.model.Game
|
||||||
import org.yuzu.yuzu_emu.model.EmulationViewModel
|
import org.yuzu.yuzu_emu.model.EmulationViewModel
|
||||||
import org.yuzu.yuzu_emu.overlay.model.OverlayControl
|
import org.yuzu.yuzu_emu.overlay.InputOverlay
|
||||||
import org.yuzu.yuzu_emu.overlay.model.OverlayLayout
|
|
||||||
import org.yuzu.yuzu_emu.utils.*
|
import org.yuzu.yuzu_emu.utils.*
|
||||||
import java.lang.NullPointerException
|
import java.lang.NullPointerException
|
||||||
|
|
||||||
class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
|
private lateinit var preferences: SharedPreferences
|
||||||
private lateinit var emulationState: EmulationState
|
private lateinit var emulationState: EmulationState
|
||||||
private var emulationActivity: EmulationActivity? = null
|
private var emulationActivity: EmulationActivity? = null
|
||||||
private var perfStatsUpdater: (() -> Unit)? = null
|
private var perfStatsUpdater: (() -> Unit)? = null
|
||||||
@ -139,6 +141,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
|
|
||||||
// So this fragment doesn't restart on configuration changes; i.e. rotation.
|
// So this fragment doesn't restart on configuration changes; i.e. rotation.
|
||||||
retainInstance = true
|
retainInstance = true
|
||||||
|
preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
|
||||||
emulationState = EmulationState(game.path)
|
emulationState = EmulationState(game.path)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,25 +382,24 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateScreenLayout()
|
updateScreenLayout()
|
||||||
val showInputOverlay = BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean()
|
|
||||||
if (emulationActivity?.isInPictureInPictureMode == true) {
|
if (emulationActivity?.isInPictureInPictureMode == true) {
|
||||||
if (binding.drawerLayout.isOpen) {
|
if (binding.drawerLayout.isOpen) {
|
||||||
binding.drawerLayout.close()
|
binding.drawerLayout.close()
|
||||||
}
|
}
|
||||||
if (showInputOverlay) {
|
if (EmulationMenuSettings.showOverlay) {
|
||||||
binding.surfaceInputOverlay.visibility = View.INVISIBLE
|
binding.surfaceInputOverlay.visibility = View.INVISIBLE
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (showInputOverlay && emulationViewModel.emulationStarted.value) {
|
if (EmulationMenuSettings.showOverlay && emulationViewModel.emulationStarted.value) {
|
||||||
binding.surfaceInputOverlay.visibility = View.VISIBLE
|
binding.surfaceInputOverlay.visibility = View.VISIBLE
|
||||||
} else {
|
} else {
|
||||||
binding.surfaceInputOverlay.visibility = View.INVISIBLE
|
binding.surfaceInputOverlay.visibility = View.INVISIBLE
|
||||||
}
|
}
|
||||||
if (!isInFoldableLayout) {
|
if (!isInFoldableLayout) {
|
||||||
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
|
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||||
binding.surfaceInputOverlay.layout = OverlayLayout.Portrait
|
binding.surfaceInputOverlay.layout = InputOverlay.PORTRAIT
|
||||||
} else {
|
} else {
|
||||||
binding.surfaceInputOverlay.layout = OverlayLayout.Landscape
|
binding.surfaceInputOverlay.layout = InputOverlay.LANDSCAPE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -421,15 +423,17 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun resetInputOverlay() {
|
private fun resetInputOverlay() {
|
||||||
IntSetting.OVERLAY_SCALE.reset()
|
preferences.edit()
|
||||||
IntSetting.OVERLAY_OPACITY.reset()
|
.remove(Settings.PREF_CONTROL_SCALE)
|
||||||
|
.remove(Settings.PREF_CONTROL_OPACITY)
|
||||||
|
.apply()
|
||||||
binding.surfaceInputOverlay.post {
|
binding.surfaceInputOverlay.post {
|
||||||
binding.surfaceInputOverlay.resetLayoutVisibilityAndPlacement()
|
binding.surfaceInputOverlay.resetLayoutVisibilityAndPlacement()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateShowFpsOverlay() {
|
private fun updateShowFpsOverlay() {
|
||||||
if (BooleanSetting.SHOW_PERFORMANCE_OVERLAY.getBoolean()) {
|
if (EmulationMenuSettings.showFps) {
|
||||||
val SYSTEM_FPS = 0
|
val SYSTEM_FPS = 0
|
||||||
val FPS = 1
|
val FPS = 1
|
||||||
val FRAMETIME = 2
|
val FRAMETIME = 2
|
||||||
@ -492,7 +496,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
binding.inGameMenu.layoutParams.height = it.bounds.bottom
|
binding.inGameMenu.layoutParams.height = it.bounds.bottom
|
||||||
|
|
||||||
isInFoldableLayout = true
|
isInFoldableLayout = true
|
||||||
binding.surfaceInputOverlay.layout = OverlayLayout.Foldable
|
binding.surfaceInputOverlay.layout = InputOverlay.FOLDABLE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
it.isSeparating
|
it.isSeparating
|
||||||
@ -531,22 +535,18 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
popup.menuInflater.inflate(R.menu.menu_overlay_options, popup.menu)
|
popup.menuInflater.inflate(R.menu.menu_overlay_options, popup.menu)
|
||||||
|
|
||||||
popup.menu.apply {
|
popup.menu.apply {
|
||||||
findItem(R.id.menu_toggle_fps).isChecked =
|
findItem(R.id.menu_toggle_fps).isChecked = EmulationMenuSettings.showFps
|
||||||
BooleanSetting.SHOW_PERFORMANCE_OVERLAY.getBoolean()
|
findItem(R.id.menu_rel_stick_center).isChecked = EmulationMenuSettings.joystickRelCenter
|
||||||
findItem(R.id.menu_rel_stick_center).isChecked =
|
findItem(R.id.menu_dpad_slide).isChecked = EmulationMenuSettings.dpadSlide
|
||||||
BooleanSetting.JOYSTICK_REL_CENTER.getBoolean()
|
findItem(R.id.menu_show_overlay).isChecked = EmulationMenuSettings.showOverlay
|
||||||
findItem(R.id.menu_dpad_slide).isChecked = BooleanSetting.DPAD_SLIDE.getBoolean()
|
findItem(R.id.menu_haptics).isChecked = EmulationMenuSettings.hapticFeedback
|
||||||
findItem(R.id.menu_show_overlay).isChecked =
|
|
||||||
BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean()
|
|
||||||
findItem(R.id.menu_haptics).isChecked = BooleanSetting.HAPTIC_FEEDBACK.getBoolean()
|
|
||||||
findItem(R.id.menu_touchscreen).isChecked = BooleanSetting.TOUCHSCREEN.getBoolean()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
popup.setOnMenuItemClickListener {
|
popup.setOnMenuItemClickListener {
|
||||||
when (it.itemId) {
|
when (it.itemId) {
|
||||||
R.id.menu_toggle_fps -> {
|
R.id.menu_toggle_fps -> {
|
||||||
it.isChecked = !it.isChecked
|
it.isChecked = !it.isChecked
|
||||||
BooleanSetting.SHOW_PERFORMANCE_OVERLAY.setBoolean(it.isChecked)
|
EmulationMenuSettings.showFps = it.isChecked
|
||||||
updateShowFpsOverlay()
|
updateShowFpsOverlay()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@ -564,12 +564,11 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
R.id.menu_toggle_controls -> {
|
R.id.menu_toggle_controls -> {
|
||||||
val overlayControlData = NativeConfig.getOverlayControlData()
|
val preferences =
|
||||||
val optionsArray = BooleanArray(overlayControlData.size)
|
PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
|
||||||
overlayControlData.forEachIndexed { i, _ ->
|
val optionsArray = BooleanArray(Settings.overlayPreferences.size)
|
||||||
optionsArray[i] = overlayControlData.firstOrNull { data ->
|
Settings.overlayPreferences.forEachIndexed { i, _ ->
|
||||||
OverlayControl.entries[i].id == data.id
|
optionsArray[i] = preferences.getBoolean("buttonToggle$i", i < 15)
|
||||||
}?.enabled == true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val dialog = MaterialAlertDialogBuilder(requireContext())
|
val dialog = MaterialAlertDialogBuilder(requireContext())
|
||||||
@ -578,13 +577,11 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
R.array.gamepadButtons,
|
R.array.gamepadButtons,
|
||||||
optionsArray
|
optionsArray
|
||||||
) { _, indexSelected, isChecked ->
|
) { _, indexSelected, isChecked ->
|
||||||
overlayControlData.firstOrNull { data ->
|
preferences.edit()
|
||||||
OverlayControl.entries[indexSelected].id == data.id
|
.putBoolean("buttonToggle$indexSelected", isChecked)
|
||||||
}?.enabled = isChecked
|
.apply()
|
||||||
}
|
}
|
||||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||||
NativeConfig.setOverlayControlData(overlayControlData)
|
|
||||||
NativeConfig.saveGlobalConfig()
|
|
||||||
binding.surfaceInputOverlay.refreshControls()
|
binding.surfaceInputOverlay.refreshControls()
|
||||||
}
|
}
|
||||||
.setNegativeButton(android.R.string.cancel, null)
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
@ -595,10 +592,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
dialog.getButton(AlertDialog.BUTTON_NEUTRAL)
|
dialog.getButton(AlertDialog.BUTTON_NEUTRAL)
|
||||||
.setOnClickListener {
|
.setOnClickListener {
|
||||||
val isChecked = !optionsArray[0]
|
val isChecked = !optionsArray[0]
|
||||||
overlayControlData.forEachIndexed { i, _ ->
|
Settings.overlayPreferences.forEachIndexed { i, _ ->
|
||||||
optionsArray[i] = isChecked
|
optionsArray[i] = isChecked
|
||||||
dialog.listView.setItemChecked(i, isChecked)
|
dialog.listView.setItemChecked(i, isChecked)
|
||||||
overlayControlData[i].enabled = isChecked
|
preferences.edit()
|
||||||
|
.putBoolean("buttonToggle$i", isChecked)
|
||||||
|
.apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
@ -606,32 +605,26 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
|
|
||||||
R.id.menu_show_overlay -> {
|
R.id.menu_show_overlay -> {
|
||||||
it.isChecked = !it.isChecked
|
it.isChecked = !it.isChecked
|
||||||
BooleanSetting.SHOW_INPUT_OVERLAY.setBoolean(it.isChecked)
|
EmulationMenuSettings.showOverlay = it.isChecked
|
||||||
binding.surfaceInputOverlay.refreshControls()
|
binding.surfaceInputOverlay.refreshControls()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.menu_rel_stick_center -> {
|
R.id.menu_rel_stick_center -> {
|
||||||
it.isChecked = !it.isChecked
|
it.isChecked = !it.isChecked
|
||||||
BooleanSetting.JOYSTICK_REL_CENTER.setBoolean(it.isChecked)
|
EmulationMenuSettings.joystickRelCenter = it.isChecked
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.menu_dpad_slide -> {
|
R.id.menu_dpad_slide -> {
|
||||||
it.isChecked = !it.isChecked
|
it.isChecked = !it.isChecked
|
||||||
BooleanSetting.DPAD_SLIDE.setBoolean(it.isChecked)
|
EmulationMenuSettings.dpadSlide = it.isChecked
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.menu_haptics -> {
|
R.id.menu_haptics -> {
|
||||||
it.isChecked = !it.isChecked
|
it.isChecked = !it.isChecked
|
||||||
BooleanSetting.HAPTIC_FEEDBACK.setBoolean(it.isChecked)
|
EmulationMenuSettings.hapticFeedback = it.isChecked
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
R.id.menu_touchscreen -> {
|
|
||||||
it.isChecked = !it.isChecked
|
|
||||||
BooleanSetting.TOUCHSCREEN.setBoolean(it.isChecked)
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -674,7 +667,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
it.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
|
it.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NativeConfig.saveGlobalConfig()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
@ -683,7 +675,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
adjustBinding.apply {
|
adjustBinding.apply {
|
||||||
inputScaleSlider.apply {
|
inputScaleSlider.apply {
|
||||||
valueTo = 150F
|
valueTo = 150F
|
||||||
value = IntSetting.OVERLAY_SCALE.getInt().toFloat()
|
value = preferences.getInt(Settings.PREF_CONTROL_SCALE, 50).toFloat()
|
||||||
addOnChangeListener(
|
addOnChangeListener(
|
||||||
Slider.OnChangeListener { _, value, _ ->
|
Slider.OnChangeListener { _, value, _ ->
|
||||||
inputScaleValue.text = "${value.toInt()}%"
|
inputScaleValue.text = "${value.toInt()}%"
|
||||||
@ -693,7 +685,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
}
|
}
|
||||||
inputOpacitySlider.apply {
|
inputOpacitySlider.apply {
|
||||||
valueTo = 100F
|
valueTo = 100F
|
||||||
value = IntSetting.OVERLAY_OPACITY.getInt().toFloat()
|
value = preferences.getInt(Settings.PREF_CONTROL_OPACITY, 100).toFloat()
|
||||||
addOnChangeListener(
|
addOnChangeListener(
|
||||||
Slider.OnChangeListener { _, value, _ ->
|
Slider.OnChangeListener { _, value, _ ->
|
||||||
inputOpacityValue.text = "${value.toInt()}%"
|
inputOpacityValue.text = "${value.toInt()}%"
|
||||||
@ -717,12 +709,16 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setControlScale(scale: Int) {
|
private fun setControlScale(scale: Int) {
|
||||||
IntSetting.OVERLAY_SCALE.setInt(scale)
|
preferences.edit()
|
||||||
|
.putInt(Settings.PREF_CONTROL_SCALE, scale)
|
||||||
|
.apply()
|
||||||
binding.surfaceInputOverlay.refreshControls()
|
binding.surfaceInputOverlay.refreshControls()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setControlOpacity(opacity: Int) {
|
private fun setControlOpacity(opacity: Int) {
|
||||||
IntSetting.OVERLAY_OPACITY.setInt(opacity)
|
preferences.edit()
|
||||||
|
.putInt(Settings.PREF_CONTROL_OPACITY, opacity)
|
||||||
|
.apply()
|
||||||
binding.surfaceInputOverlay.refreshControls()
|
binding.surfaceInputOverlay.refreshControls()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -10,7 +10,6 @@ import android.graphics.Rect
|
|||||||
import android.graphics.drawable.BitmapDrawable
|
import android.graphics.drawable.BitmapDrawable
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import org.yuzu.yuzu_emu.NativeLibrary.ButtonState
|
import org.yuzu.yuzu_emu.NativeLibrary.ButtonState
|
||||||
import org.yuzu.yuzu_emu.overlay.model.OverlayControlData
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom [BitmapDrawable] that is capable
|
* Custom [BitmapDrawable] that is capable
|
||||||
@ -26,7 +25,7 @@ class InputOverlayDrawableButton(
|
|||||||
defaultStateBitmap: Bitmap,
|
defaultStateBitmap: Bitmap,
|
||||||
pressedStateBitmap: Bitmap,
|
pressedStateBitmap: Bitmap,
|
||||||
val buttonId: Int,
|
val buttonId: Int,
|
||||||
val overlayControlData: OverlayControlData
|
val prefId: String
|
||||||
) {
|
) {
|
||||||
// The ID value what motion event is tracking
|
// The ID value what motion event is tracking
|
||||||
var trackId: Int
|
var trackId: Int
|
||||||
|
@ -14,7 +14,7 @@ import kotlin.math.cos
|
|||||||
import kotlin.math.sin
|
import kotlin.math.sin
|
||||||
import kotlin.math.sqrt
|
import kotlin.math.sqrt
|
||||||
import org.yuzu.yuzu_emu.NativeLibrary
|
import org.yuzu.yuzu_emu.NativeLibrary
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
|
import org.yuzu.yuzu_emu.utils.EmulationMenuSettings
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom [BitmapDrawable] that is capable
|
* Custom [BitmapDrawable] that is capable
|
||||||
@ -125,7 +125,7 @@ class InputOverlayDrawableJoystick(
|
|||||||
pressedState = true
|
pressedState = true
|
||||||
outerBitmap.alpha = 0
|
outerBitmap.alpha = 0
|
||||||
boundsBoxBitmap.alpha = opacity
|
boundsBoxBitmap.alpha = opacity
|
||||||
if (BooleanSetting.JOYSTICK_REL_CENTER.getBoolean()) {
|
if (EmulationMenuSettings.joystickRelCenter) {
|
||||||
virtBounds.offset(
|
virtBounds.offset(
|
||||||
xPosition - virtBounds.centerX(),
|
xPosition - virtBounds.centerX(),
|
||||||
yPosition - virtBounds.centerY()
|
yPosition - virtBounds.centerY()
|
||||||
|
@ -1,188 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.overlay.model
|
|
||||||
|
|
||||||
import androidx.annotation.IntegerRes
|
|
||||||
import org.yuzu.yuzu_emu.R
|
|
||||||
import org.yuzu.yuzu_emu.YuzuApplication
|
|
||||||
|
|
||||||
enum class OverlayControl(
|
|
||||||
val id: String,
|
|
||||||
val defaultVisibility: Boolean,
|
|
||||||
@IntegerRes val defaultLandscapePositionResources: Pair<Int, Int>,
|
|
||||||
@IntegerRes val defaultPortraitPositionResources: Pair<Int, Int>,
|
|
||||||
@IntegerRes val defaultFoldablePositionResources: Pair<Int, Int>
|
|
||||||
) {
|
|
||||||
BUTTON_A(
|
|
||||||
"button_a",
|
|
||||||
true,
|
|
||||||
Pair(R.integer.BUTTON_A_X, R.integer.BUTTON_A_Y),
|
|
||||||
Pair(R.integer.BUTTON_A_X_PORTRAIT, R.integer.BUTTON_A_Y_PORTRAIT),
|
|
||||||
Pair(R.integer.BUTTON_A_X_FOLDABLE, R.integer.BUTTON_A_Y_FOLDABLE)
|
|
||||||
),
|
|
||||||
BUTTON_B(
|
|
||||||
"button_b",
|
|
||||||
true,
|
|
||||||
Pair(R.integer.BUTTON_B_X, R.integer.BUTTON_B_Y),
|
|
||||||
Pair(R.integer.BUTTON_B_X_PORTRAIT, R.integer.BUTTON_B_Y_PORTRAIT),
|
|
||||||
Pair(R.integer.BUTTON_B_X_FOLDABLE, R.integer.BUTTON_B_Y_FOLDABLE)
|
|
||||||
),
|
|
||||||
BUTTON_X(
|
|
||||||
"button_x",
|
|
||||||
true,
|
|
||||||
Pair(R.integer.BUTTON_X_X, R.integer.BUTTON_X_Y),
|
|
||||||
Pair(R.integer.BUTTON_X_X_PORTRAIT, R.integer.BUTTON_X_Y_PORTRAIT),
|
|
||||||
Pair(R.integer.BUTTON_X_X_FOLDABLE, R.integer.BUTTON_X_Y_FOLDABLE)
|
|
||||||
),
|
|
||||||
BUTTON_Y(
|
|
||||||
"button_y",
|
|
||||||
true,
|
|
||||||
Pair(R.integer.BUTTON_Y_X, R.integer.BUTTON_Y_Y),
|
|
||||||
Pair(R.integer.BUTTON_Y_X_PORTRAIT, R.integer.BUTTON_Y_Y_PORTRAIT),
|
|
||||||
Pair(R.integer.BUTTON_Y_X_FOLDABLE, R.integer.BUTTON_Y_Y_FOLDABLE)
|
|
||||||
),
|
|
||||||
BUTTON_PLUS(
|
|
||||||
"button_plus",
|
|
||||||
true,
|
|
||||||
Pair(R.integer.BUTTON_PLUS_X, R.integer.BUTTON_PLUS_Y),
|
|
||||||
Pair(R.integer.BUTTON_PLUS_X_PORTRAIT, R.integer.BUTTON_PLUS_Y_PORTRAIT),
|
|
||||||
Pair(R.integer.BUTTON_PLUS_X_FOLDABLE, R.integer.BUTTON_PLUS_Y_FOLDABLE)
|
|
||||||
),
|
|
||||||
BUTTON_MINUS(
|
|
||||||
"button_minus",
|
|
||||||
true,
|
|
||||||
Pair(R.integer.BUTTON_MINUS_X, R.integer.BUTTON_MINUS_Y),
|
|
||||||
Pair(R.integer.BUTTON_MINUS_X_PORTRAIT, R.integer.BUTTON_MINUS_Y_PORTRAIT),
|
|
||||||
Pair(R.integer.BUTTON_MINUS_X_FOLDABLE, R.integer.BUTTON_MINUS_Y_FOLDABLE)
|
|
||||||
),
|
|
||||||
BUTTON_HOME(
|
|
||||||
"button_home",
|
|
||||||
false,
|
|
||||||
Pair(R.integer.BUTTON_HOME_X, R.integer.BUTTON_HOME_Y),
|
|
||||||
Pair(R.integer.BUTTON_HOME_X_PORTRAIT, R.integer.BUTTON_HOME_Y_PORTRAIT),
|
|
||||||
Pair(R.integer.BUTTON_HOME_X_FOLDABLE, R.integer.BUTTON_HOME_Y_FOLDABLE)
|
|
||||||
),
|
|
||||||
BUTTON_CAPTURE(
|
|
||||||
"button_capture",
|
|
||||||
false,
|
|
||||||
Pair(R.integer.BUTTON_CAPTURE_X, R.integer.BUTTON_CAPTURE_Y),
|
|
||||||
Pair(R.integer.BUTTON_CAPTURE_X_PORTRAIT, R.integer.BUTTON_CAPTURE_Y_PORTRAIT),
|
|
||||||
Pair(R.integer.BUTTON_CAPTURE_X_FOLDABLE, R.integer.BUTTON_CAPTURE_Y_FOLDABLE)
|
|
||||||
),
|
|
||||||
BUTTON_L(
|
|
||||||
"button_l",
|
|
||||||
true,
|
|
||||||
Pair(R.integer.BUTTON_L_X, R.integer.BUTTON_L_Y),
|
|
||||||
Pair(R.integer.BUTTON_L_X_PORTRAIT, R.integer.BUTTON_L_Y_PORTRAIT),
|
|
||||||
Pair(R.integer.BUTTON_L_X_FOLDABLE, R.integer.BUTTON_L_Y_FOLDABLE)
|
|
||||||
),
|
|
||||||
BUTTON_R(
|
|
||||||
"button_r",
|
|
||||||
true,
|
|
||||||
Pair(R.integer.BUTTON_R_X, R.integer.BUTTON_R_Y),
|
|
||||||
Pair(R.integer.BUTTON_R_X_PORTRAIT, R.integer.BUTTON_R_Y_PORTRAIT),
|
|
||||||
Pair(R.integer.BUTTON_R_X_FOLDABLE, R.integer.BUTTON_R_Y_FOLDABLE)
|
|
||||||
),
|
|
||||||
BUTTON_ZL(
|
|
||||||
"button_zl",
|
|
||||||
true,
|
|
||||||
Pair(R.integer.BUTTON_ZL_X, R.integer.BUTTON_ZL_Y),
|
|
||||||
Pair(R.integer.BUTTON_ZL_X_PORTRAIT, R.integer.BUTTON_ZL_Y_PORTRAIT),
|
|
||||||
Pair(R.integer.BUTTON_ZL_X_FOLDABLE, R.integer.BUTTON_ZL_Y_FOLDABLE)
|
|
||||||
),
|
|
||||||
BUTTON_ZR(
|
|
||||||
"button_zr",
|
|
||||||
true,
|
|
||||||
Pair(R.integer.BUTTON_ZR_X, R.integer.BUTTON_ZR_Y),
|
|
||||||
Pair(R.integer.BUTTON_ZR_X_PORTRAIT, R.integer.BUTTON_ZR_Y_PORTRAIT),
|
|
||||||
Pair(R.integer.BUTTON_ZR_X_FOLDABLE, R.integer.BUTTON_ZR_Y_FOLDABLE)
|
|
||||||
),
|
|
||||||
BUTTON_STICK_L(
|
|
||||||
"button_stick_l",
|
|
||||||
true,
|
|
||||||
Pair(R.integer.BUTTON_STICK_L_X, R.integer.BUTTON_STICK_L_Y),
|
|
||||||
Pair(R.integer.BUTTON_STICK_L_X_PORTRAIT, R.integer.BUTTON_STICK_L_Y_PORTRAIT),
|
|
||||||
Pair(R.integer.BUTTON_STICK_L_X_FOLDABLE, R.integer.BUTTON_STICK_L_Y_FOLDABLE)
|
|
||||||
),
|
|
||||||
BUTTON_STICK_R(
|
|
||||||
"button_stick_r",
|
|
||||||
true,
|
|
||||||
Pair(R.integer.BUTTON_STICK_R_X, R.integer.BUTTON_STICK_R_Y),
|
|
||||||
Pair(R.integer.BUTTON_STICK_R_X_PORTRAIT, R.integer.BUTTON_STICK_R_Y_PORTRAIT),
|
|
||||||
Pair(R.integer.BUTTON_STICK_R_X_FOLDABLE, R.integer.BUTTON_STICK_R_Y_FOLDABLE)
|
|
||||||
),
|
|
||||||
STICK_L(
|
|
||||||
"stick_l",
|
|
||||||
true,
|
|
||||||
Pair(R.integer.STICK_L_X, R.integer.STICK_L_Y),
|
|
||||||
Pair(R.integer.STICK_L_X_PORTRAIT, R.integer.STICK_L_Y_PORTRAIT),
|
|
||||||
Pair(R.integer.STICK_L_X_FOLDABLE, R.integer.STICK_L_Y_FOLDABLE)
|
|
||||||
),
|
|
||||||
STICK_R(
|
|
||||||
"stick_r",
|
|
||||||
true,
|
|
||||||
Pair(R.integer.STICK_R_X, R.integer.STICK_R_Y),
|
|
||||||
Pair(R.integer.STICK_R_X_PORTRAIT, R.integer.STICK_R_Y_PORTRAIT),
|
|
||||||
Pair(R.integer.STICK_R_X_FOLDABLE, R.integer.STICK_R_Y_FOLDABLE)
|
|
||||||
),
|
|
||||||
COMBINED_DPAD(
|
|
||||||
"combined_dpad",
|
|
||||||
true,
|
|
||||||
Pair(R.integer.COMBINED_DPAD_X, R.integer.COMBINED_DPAD_Y),
|
|
||||||
Pair(R.integer.COMBINED_DPAD_X_PORTRAIT, R.integer.COMBINED_DPAD_Y_PORTRAIT),
|
|
||||||
Pair(R.integer.COMBINED_DPAD_X_FOLDABLE, R.integer.COMBINED_DPAD_Y_FOLDABLE)
|
|
||||||
);
|
|
||||||
|
|
||||||
fun getDefaultPositionForLayout(layout: OverlayLayout): Pair<Double, Double> {
|
|
||||||
val rawResourcePair: Pair<Int, Int>
|
|
||||||
YuzuApplication.appContext.resources.apply {
|
|
||||||
rawResourcePair = when (layout) {
|
|
||||||
OverlayLayout.Landscape -> {
|
|
||||||
Pair(
|
|
||||||
getInteger(this@OverlayControl.defaultLandscapePositionResources.first),
|
|
||||||
getInteger(this@OverlayControl.defaultLandscapePositionResources.second)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
OverlayLayout.Portrait -> {
|
|
||||||
Pair(
|
|
||||||
getInteger(this@OverlayControl.defaultPortraitPositionResources.first),
|
|
||||||
getInteger(this@OverlayControl.defaultPortraitPositionResources.second)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
OverlayLayout.Foldable -> {
|
|
||||||
Pair(
|
|
||||||
getInteger(this@OverlayControl.defaultFoldablePositionResources.first),
|
|
||||||
getInteger(this@OverlayControl.defaultFoldablePositionResources.second)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Pair(
|
|
||||||
rawResourcePair.first.toDouble() / 1000,
|
|
||||||
rawResourcePair.second.toDouble() / 1000
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun toOverlayControlData(): OverlayControlData =
|
|
||||||
OverlayControlData(
|
|
||||||
id,
|
|
||||||
defaultVisibility,
|
|
||||||
getDefaultPositionForLayout(OverlayLayout.Landscape),
|
|
||||||
getDefaultPositionForLayout(OverlayLayout.Portrait),
|
|
||||||
getDefaultPositionForLayout(OverlayLayout.Foldable)
|
|
||||||
)
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val map: HashMap<String, OverlayControl> by lazy {
|
|
||||||
val hashMap = hashMapOf<String, OverlayControl>()
|
|
||||||
entries.forEach { hashMap[it.id] = it }
|
|
||||||
hashMap
|
|
||||||
}
|
|
||||||
|
|
||||||
fun from(id: String): OverlayControl? = map[id]
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.overlay.model
|
|
||||||
|
|
||||||
data class OverlayControlData(
|
|
||||||
val id: String,
|
|
||||||
var enabled: Boolean,
|
|
||||||
var landscapePosition: Pair<Double, Double>,
|
|
||||||
var portraitPosition: Pair<Double, Double>,
|
|
||||||
var foldablePosition: Pair<Double, Double>
|
|
||||||
) {
|
|
||||||
fun positionFromLayout(layout: OverlayLayout): Pair<Double, Double> =
|
|
||||||
when (layout) {
|
|
||||||
OverlayLayout.Landscape -> landscapePosition
|
|
||||||
OverlayLayout.Portrait -> portraitPosition
|
|
||||||
OverlayLayout.Foldable -> foldablePosition
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.overlay.model
|
|
||||||
|
|
||||||
import androidx.annotation.IntegerRes
|
|
||||||
|
|
||||||
data class OverlayControlDefault(
|
|
||||||
val buttonId: String,
|
|
||||||
@IntegerRes val landscapePositionResource: Pair<Int, Int>,
|
|
||||||
@IntegerRes val portraitPositionResource: Pair<Int, Int>,
|
|
||||||
@IntegerRes val foldablePositionResource: Pair<Int, Int>
|
|
||||||
)
|
|
@ -1,10 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.overlay.model
|
|
||||||
|
|
||||||
enum class OverlayLayout(val id: String) {
|
|
||||||
Landscape("Landscape"),
|
|
||||||
Portrait("Portrait"),
|
|
||||||
Foldable("Foldable")
|
|
||||||
}
|
|
@ -91,20 +91,18 @@ class GamesFragment : Fragment() {
|
|||||||
viewLifecycleOwner.lifecycleScope.apply {
|
viewLifecycleOwner.lifecycleScope.apply {
|
||||||
launch {
|
launch {
|
||||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||||
gamesViewModel.isReloading.collect {
|
gamesViewModel.isReloading.collect { binding.swipeRefresh.isRefreshing = it }
|
||||||
binding.swipeRefresh.isRefreshing = it
|
|
||||||
if (gamesViewModel.games.value.isEmpty() && !it) {
|
|
||||||
binding.noticeText.visibility = View.VISIBLE
|
|
||||||
} else {
|
|
||||||
binding.noticeText.visibility = View.INVISIBLE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
launch {
|
launch {
|
||||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||||
gamesViewModel.games.collectLatest {
|
gamesViewModel.games.collectLatest {
|
||||||
(binding.gridGames.adapter as GameAdapter).submitList(it)
|
(binding.gridGames.adapter as GameAdapter).submitList(it)
|
||||||
|
if (it.isEmpty()) {
|
||||||
|
binding.noticeText.visibility = View.VISIBLE
|
||||||
|
} else {
|
||||||
|
binding.noticeText.visibility = View.GONE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,17 +3,9 @@
|
|||||||
|
|
||||||
package org.yuzu.yuzu_emu.utils
|
package org.yuzu.yuzu_emu.utils
|
||||||
|
|
||||||
import androidx.preference.PreferenceManager
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import org.yuzu.yuzu_emu.NativeLibrary
|
import org.yuzu.yuzu_emu.NativeLibrary
|
||||||
import org.yuzu.yuzu_emu.YuzuApplication
|
import org.yuzu.yuzu_emu.YuzuApplication
|
||||||
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.Settings
|
|
||||||
import org.yuzu.yuzu_emu.overlay.model.OverlayControlData
|
|
||||||
import org.yuzu.yuzu_emu.overlay.model.OverlayControl
|
|
||||||
import org.yuzu.yuzu_emu.overlay.model.OverlayLayout
|
|
||||||
import org.yuzu.yuzu_emu.utils.PreferenceUtil.migratePreference
|
|
||||||
|
|
||||||
object DirectoryInitialization {
|
object DirectoryInitialization {
|
||||||
private var userPath: String? = null
|
private var userPath: String? = null
|
||||||
@ -25,7 +17,6 @@ object DirectoryInitialization {
|
|||||||
initializeInternalStorage()
|
initializeInternalStorage()
|
||||||
NativeLibrary.initializeSystem(false)
|
NativeLibrary.initializeSystem(false)
|
||||||
NativeConfig.initializeGlobalConfig()
|
NativeConfig.initializeGlobalConfig()
|
||||||
migrateSettings()
|
|
||||||
areDirectoriesReady = true
|
areDirectoriesReady = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -44,170 +35,4 @@ object DirectoryInitialization {
|
|||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun migrateSettings() {
|
|
||||||
val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
|
|
||||||
var saveConfig = false
|
|
||||||
val theme = preferences.migratePreference<Int>(Settings.PREF_THEME)
|
|
||||||
if (theme != null) {
|
|
||||||
IntSetting.THEME.setInt(theme)
|
|
||||||
saveConfig = true
|
|
||||||
}
|
|
||||||
|
|
||||||
val themeMode = preferences.migratePreference<Int>(Settings.PREF_THEME_MODE)
|
|
||||||
if (themeMode != null) {
|
|
||||||
IntSetting.THEME_MODE.setInt(themeMode)
|
|
||||||
saveConfig = true
|
|
||||||
}
|
|
||||||
|
|
||||||
val blackBackgrounds =
|
|
||||||
preferences.migratePreference<Boolean>(Settings.PREF_BLACK_BACKGROUNDS)
|
|
||||||
if (blackBackgrounds != null) {
|
|
||||||
BooleanSetting.BLACK_BACKGROUNDS.setBoolean(blackBackgrounds)
|
|
||||||
saveConfig = true
|
|
||||||
}
|
|
||||||
|
|
||||||
val joystickRelCenter =
|
|
||||||
preferences.migratePreference<Boolean>(Settings.PREF_MENU_SETTINGS_JOYSTICK_REL_CENTER)
|
|
||||||
if (joystickRelCenter != null) {
|
|
||||||
BooleanSetting.JOYSTICK_REL_CENTER.setBoolean(joystickRelCenter)
|
|
||||||
saveConfig = true
|
|
||||||
}
|
|
||||||
|
|
||||||
val dpadSlide =
|
|
||||||
preferences.migratePreference<Boolean>(Settings.PREF_MENU_SETTINGS_DPAD_SLIDE)
|
|
||||||
if (dpadSlide != null) {
|
|
||||||
BooleanSetting.DPAD_SLIDE.setBoolean(dpadSlide)
|
|
||||||
saveConfig = true
|
|
||||||
}
|
|
||||||
|
|
||||||
val hapticFeedback =
|
|
||||||
preferences.migratePreference<Boolean>(Settings.PREF_MENU_SETTINGS_HAPTICS)
|
|
||||||
if (hapticFeedback != null) {
|
|
||||||
BooleanSetting.HAPTIC_FEEDBACK.setBoolean(hapticFeedback)
|
|
||||||
saveConfig = true
|
|
||||||
}
|
|
||||||
|
|
||||||
val showPerformanceOverlay =
|
|
||||||
preferences.migratePreference<Boolean>(Settings.PREF_MENU_SETTINGS_SHOW_FPS)
|
|
||||||
if (showPerformanceOverlay != null) {
|
|
||||||
BooleanSetting.SHOW_PERFORMANCE_OVERLAY.setBoolean(showPerformanceOverlay)
|
|
||||||
saveConfig = true
|
|
||||||
}
|
|
||||||
|
|
||||||
val showInputOverlay =
|
|
||||||
preferences.migratePreference<Boolean>(Settings.PREF_MENU_SETTINGS_SHOW_OVERLAY)
|
|
||||||
if (showInputOverlay != null) {
|
|
||||||
BooleanSetting.SHOW_INPUT_OVERLAY.setBoolean(showInputOverlay)
|
|
||||||
saveConfig = true
|
|
||||||
}
|
|
||||||
|
|
||||||
val overlayOpacity = preferences.migratePreference<Int>(Settings.PREF_CONTROL_OPACITY)
|
|
||||||
if (overlayOpacity != null) {
|
|
||||||
IntSetting.OVERLAY_OPACITY.setInt(overlayOpacity)
|
|
||||||
saveConfig = true
|
|
||||||
}
|
|
||||||
|
|
||||||
val overlayScale = preferences.migratePreference<Int>(Settings.PREF_CONTROL_SCALE)
|
|
||||||
if (overlayScale != null) {
|
|
||||||
IntSetting.OVERLAY_SCALE.setInt(overlayScale)
|
|
||||||
saveConfig = true
|
|
||||||
}
|
|
||||||
|
|
||||||
var setOverlayData = false
|
|
||||||
val overlayControlData = NativeConfig.getOverlayControlData()
|
|
||||||
if (overlayControlData.isEmpty()) {
|
|
||||||
val overlayControlDataMap =
|
|
||||||
NativeConfig.getOverlayControlData().associateBy { it.id }.toMutableMap()
|
|
||||||
for (button in Settings.overlayPreferences) {
|
|
||||||
val buttonId = convertButtonId(button)
|
|
||||||
var buttonEnabled = preferences.migratePreference<Boolean>(button)
|
|
||||||
if (buttonEnabled == null) {
|
|
||||||
buttonEnabled = OverlayControl.map[buttonId]?.defaultVisibility == true
|
|
||||||
}
|
|
||||||
|
|
||||||
var landscapeXPosition = preferences.migratePreference<Float>(
|
|
||||||
"$button-X${Settings.PREF_LANDSCAPE_SUFFIX}"
|
|
||||||
)?.toDouble()
|
|
||||||
var landscapeYPosition = preferences.migratePreference<Float>(
|
|
||||||
"$button-Y${Settings.PREF_LANDSCAPE_SUFFIX}"
|
|
||||||
)?.toDouble()
|
|
||||||
if (landscapeXPosition == null || landscapeYPosition == null) {
|
|
||||||
val landscapePosition = OverlayControl.map[buttonId]
|
|
||||||
?.getDefaultPositionForLayout(OverlayLayout.Landscape) ?: Pair(0.0, 0.0)
|
|
||||||
landscapeXPosition = landscapePosition.first
|
|
||||||
landscapeYPosition = landscapePosition.second
|
|
||||||
}
|
|
||||||
|
|
||||||
var portraitXPosition = preferences.migratePreference<Float>(
|
|
||||||
"$button-X${Settings.PREF_PORTRAIT_SUFFIX}"
|
|
||||||
)?.toDouble()
|
|
||||||
var portraitYPosition = preferences.migratePreference<Float>(
|
|
||||||
"$button-Y${Settings.PREF_PORTRAIT_SUFFIX}"
|
|
||||||
)?.toDouble()
|
|
||||||
if (portraitXPosition == null || portraitYPosition == null) {
|
|
||||||
val portraitPosition = OverlayControl.map[buttonId]
|
|
||||||
?.getDefaultPositionForLayout(OverlayLayout.Portrait) ?: Pair(0.0, 0.0)
|
|
||||||
portraitXPosition = portraitPosition.first
|
|
||||||
portraitYPosition = portraitPosition.second
|
|
||||||
}
|
|
||||||
|
|
||||||
var foldableXPosition = preferences.migratePreference<Float>(
|
|
||||||
"$button-X${Settings.PREF_FOLDABLE_SUFFIX}"
|
|
||||||
)?.toDouble()
|
|
||||||
var foldableYPosition = preferences.migratePreference<Float>(
|
|
||||||
"$button-Y${Settings.PREF_FOLDABLE_SUFFIX}"
|
|
||||||
)?.toDouble()
|
|
||||||
if (foldableXPosition == null || foldableYPosition == null) {
|
|
||||||
val foldablePosition = OverlayControl.map[buttonId]
|
|
||||||
?.getDefaultPositionForLayout(OverlayLayout.Foldable) ?: Pair(0.0, 0.0)
|
|
||||||
foldableXPosition = foldablePosition.first
|
|
||||||
foldableYPosition = foldablePosition.second
|
|
||||||
}
|
|
||||||
|
|
||||||
val controlData = OverlayControlData(
|
|
||||||
buttonId,
|
|
||||||
buttonEnabled,
|
|
||||||
Pair(landscapeXPosition, landscapeYPosition),
|
|
||||||
Pair(portraitXPosition, portraitYPosition),
|
|
||||||
Pair(foldableXPosition, foldableYPosition)
|
|
||||||
)
|
|
||||||
overlayControlDataMap[buttonId] = controlData
|
|
||||||
setOverlayData = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (setOverlayData) {
|
|
||||||
NativeConfig.setOverlayControlData(
|
|
||||||
overlayControlDataMap.map { it.value }.toTypedArray()
|
|
||||||
)
|
|
||||||
saveConfig = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (saveConfig) {
|
|
||||||
NativeConfig.saveGlobalConfig()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun convertButtonId(buttonId: String): String =
|
|
||||||
when (buttonId) {
|
|
||||||
Settings.PREF_BUTTON_A -> OverlayControl.BUTTON_A.id
|
|
||||||
Settings.PREF_BUTTON_B -> OverlayControl.BUTTON_B.id
|
|
||||||
Settings.PREF_BUTTON_X -> OverlayControl.BUTTON_X.id
|
|
||||||
Settings.PREF_BUTTON_Y -> OverlayControl.BUTTON_Y.id
|
|
||||||
Settings.PREF_BUTTON_L -> OverlayControl.BUTTON_L.id
|
|
||||||
Settings.PREF_BUTTON_R -> OverlayControl.BUTTON_R.id
|
|
||||||
Settings.PREF_BUTTON_ZL -> OverlayControl.BUTTON_ZL.id
|
|
||||||
Settings.PREF_BUTTON_ZR -> OverlayControl.BUTTON_ZR.id
|
|
||||||
Settings.PREF_BUTTON_PLUS -> OverlayControl.BUTTON_PLUS.id
|
|
||||||
Settings.PREF_BUTTON_MINUS -> OverlayControl.BUTTON_MINUS.id
|
|
||||||
Settings.PREF_BUTTON_DPAD -> OverlayControl.COMBINED_DPAD.id
|
|
||||||
Settings.PREF_STICK_L -> OverlayControl.STICK_L.id
|
|
||||||
Settings.PREF_STICK_R -> OverlayControl.STICK_R.id
|
|
||||||
Settings.PREF_BUTTON_HOME -> OverlayControl.BUTTON_HOME.id
|
|
||||||
Settings.PREF_BUTTON_SCREENSHOT -> OverlayControl.BUTTON_CAPTURE.id
|
|
||||||
Settings.PREF_BUTTON_STICK_L -> OverlayControl.BUTTON_STICK_L.id
|
|
||||||
Settings.PREF_BUTTON_STICK_R -> OverlayControl.BUTTON_STICK_R.id
|
|
||||||
else -> ""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,50 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
package org.yuzu.yuzu_emu.utils
|
||||||
|
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
|
import org.yuzu.yuzu_emu.YuzuApplication
|
||||||
|
import org.yuzu.yuzu_emu.features.settings.model.Settings
|
||||||
|
|
||||||
|
object EmulationMenuSettings {
|
||||||
|
private val preferences =
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
|
||||||
|
|
||||||
|
var joystickRelCenter: Boolean
|
||||||
|
get() = preferences.getBoolean(Settings.PREF_MENU_SETTINGS_JOYSTICK_REL_CENTER, true)
|
||||||
|
set(value) {
|
||||||
|
preferences.edit()
|
||||||
|
.putBoolean(Settings.PREF_MENU_SETTINGS_JOYSTICK_REL_CENTER, value)
|
||||||
|
.apply()
|
||||||
|
}
|
||||||
|
var dpadSlide: Boolean
|
||||||
|
get() = preferences.getBoolean(Settings.PREF_MENU_SETTINGS_DPAD_SLIDE, true)
|
||||||
|
set(value) {
|
||||||
|
preferences.edit()
|
||||||
|
.putBoolean(Settings.PREF_MENU_SETTINGS_DPAD_SLIDE, value)
|
||||||
|
.apply()
|
||||||
|
}
|
||||||
|
var hapticFeedback: Boolean
|
||||||
|
get() = preferences.getBoolean(Settings.PREF_MENU_SETTINGS_HAPTICS, false)
|
||||||
|
set(value) {
|
||||||
|
preferences.edit()
|
||||||
|
.putBoolean(Settings.PREF_MENU_SETTINGS_HAPTICS, value)
|
||||||
|
.apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
var showFps: Boolean
|
||||||
|
get() = preferences.getBoolean(Settings.PREF_MENU_SETTINGS_SHOW_FPS, false)
|
||||||
|
set(value) {
|
||||||
|
preferences.edit()
|
||||||
|
.putBoolean(Settings.PREF_MENU_SETTINGS_SHOW_FPS, value)
|
||||||
|
.apply()
|
||||||
|
}
|
||||||
|
var showOverlay: Boolean
|
||||||
|
get() = preferences.getBoolean(Settings.PREF_MENU_SETTINGS_SHOW_OVERLAY, true)
|
||||||
|
set(value) {
|
||||||
|
preferences.edit()
|
||||||
|
.putBoolean(Settings.PREF_MENU_SETTINGS_SHOW_OVERLAY, value)
|
||||||
|
.apply()
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,6 @@
|
|||||||
package org.yuzu.yuzu_emu.utils
|
package org.yuzu.yuzu_emu.utils
|
||||||
|
|
||||||
import org.yuzu.yuzu_emu.model.GameDir
|
import org.yuzu.yuzu_emu.model.GameDir
|
||||||
import org.yuzu.yuzu_emu.overlay.model.OverlayControlData
|
|
||||||
|
|
||||||
object NativeConfig {
|
object NativeConfig {
|
||||||
/**
|
/**
|
||||||
@ -151,21 +150,4 @@ object NativeConfig {
|
|||||||
*/
|
*/
|
||||||
@Synchronized
|
@Synchronized
|
||||||
external fun setDisabledAddons(programId: String, disabledAddons: Array<String>)
|
external fun setDisabledAddons(programId: String, disabledAddons: Array<String>)
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets an array of [OverlayControlData] from settings
|
|
||||||
*
|
|
||||||
* @return An array of [OverlayControlData]
|
|
||||||
*/
|
|
||||||
@Synchronized
|
|
||||||
external fun getOverlayControlData(): Array<OverlayControlData>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears the AndroidSettings::values.overlay_control_data array and replaces its values
|
|
||||||
* with [overlayControlData]
|
|
||||||
*
|
|
||||||
* @param overlayControlData Replacement array of [OverlayControlData]
|
|
||||||
*/
|
|
||||||
@Synchronized
|
|
||||||
external fun setOverlayControlData(overlayControlData: Array<OverlayControlData>)
|
|
||||||
}
|
}
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.utils
|
|
||||||
|
|
||||||
import android.content.SharedPreferences
|
|
||||||
|
|
||||||
object PreferenceUtil {
|
|
||||||
/**
|
|
||||||
* Retrieves a shared preference value and then deletes the value in storage.
|
|
||||||
* @param key Associated key for the value in this preferences instance
|
|
||||||
* @return Typed value associated with [key]. Null if no such key exists.
|
|
||||||
*/
|
|
||||||
inline fun <reified T> SharedPreferences.migratePreference(key: String): T? {
|
|
||||||
if (!this.contains(key)) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
val value: Any = when (T::class) {
|
|
||||||
String::class -> this.getString(key, "")!!
|
|
||||||
|
|
||||||
Boolean::class -> this.getBoolean(key, false)
|
|
||||||
|
|
||||||
Int::class -> this.getInt(key, 0)
|
|
||||||
|
|
||||||
Float::class -> this.getFloat(key, 0f)
|
|
||||||
|
|
||||||
Long::class -> this.getLong(key, 0)
|
|
||||||
|
|
||||||
else -> throw IllegalStateException("Tried to migrate preference with invalid type!")
|
|
||||||
}
|
|
||||||
deletePreference(key)
|
|
||||||
return value as T
|
|
||||||
}
|
|
||||||
|
|
||||||
fun SharedPreferences.deletePreference(key: String) = this.edit().remove(key).apply()
|
|
||||||
}
|
|
@ -5,38 +5,38 @@ package org.yuzu.yuzu_emu.utils
|
|||||||
|
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.os.Build
|
|
||||||
import androidx.annotation.ColorInt
|
import androidx.annotation.ColorInt
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
import androidx.core.view.WindowInsetsControllerCompat
|
import androidx.core.view.WindowInsetsControllerCompat
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
|
import org.yuzu.yuzu_emu.YuzuApplication
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
|
import org.yuzu.yuzu_emu.features.settings.model.Settings
|
||||||
import org.yuzu.yuzu_emu.ui.main.ThemeProvider
|
import org.yuzu.yuzu_emu.ui.main.ThemeProvider
|
||||||
|
|
||||||
object ThemeHelper {
|
object ThemeHelper {
|
||||||
const val SYSTEM_BAR_ALPHA = 0.9f
|
const val SYSTEM_BAR_ALPHA = 0.9f
|
||||||
|
|
||||||
|
private const val DEFAULT = 0
|
||||||
|
private const val MATERIAL_YOU = 1
|
||||||
|
|
||||||
fun setTheme(activity: AppCompatActivity) {
|
fun setTheme(activity: AppCompatActivity) {
|
||||||
|
val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
|
||||||
setThemeMode(activity)
|
setThemeMode(activity)
|
||||||
when (Theme.from(IntSetting.THEME.getInt())) {
|
when (preferences.getInt(Settings.PREF_THEME, 0)) {
|
||||||
Theme.Default -> activity.setTheme(R.style.Theme_Yuzu_Main)
|
DEFAULT -> activity.setTheme(R.style.Theme_Yuzu_Main)
|
||||||
Theme.MaterialYou -> {
|
MATERIAL_YOU -> activity.setTheme(R.style.Theme_Yuzu_Main_MaterialYou)
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
||||||
activity.setTheme(R.style.Theme_Yuzu_Main_MaterialYou)
|
|
||||||
} else {
|
|
||||||
activity.setTheme(R.style.Theme_Yuzu_Main)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Using a specific night mode check because this could apply incorrectly when using the
|
// Using a specific night mode check because this could apply incorrectly when using the
|
||||||
// light app mode, dark system mode, and black backgrounds. Launching the settings activity
|
// light app mode, dark system mode, and black backgrounds. Launching the settings activity
|
||||||
// will then show light mode colors/navigation bars but with black backgrounds.
|
// will then show light mode colors/navigation bars but with black backgrounds.
|
||||||
if (BooleanSetting.BLACK_BACKGROUNDS.getBoolean() && isNightMode(activity)) {
|
if (preferences.getBoolean(Settings.PREF_BLACK_BACKGROUNDS, false) &&
|
||||||
|
isNightMode(activity)
|
||||||
|
) {
|
||||||
activity.setTheme(R.style.ThemeOverlay_Yuzu_Dark)
|
activity.setTheme(R.style.ThemeOverlay_Yuzu_Dark)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -60,7 +60,8 @@ object ThemeHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun setThemeMode(activity: AppCompatActivity) {
|
fun setThemeMode(activity: AppCompatActivity) {
|
||||||
val themeMode = IntSetting.THEME_MODE.getInt()
|
val themeMode = PreferenceManager.getDefaultSharedPreferences(activity.applicationContext)
|
||||||
|
.getInt(Settings.PREF_THEME_MODE, AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
||||||
activity.delegate.localNightMode = themeMode
|
activity.delegate.localNightMode = themeMode
|
||||||
val windowController = WindowCompat.getInsetsController(
|
val windowController = WindowCompat.getInsetsController(
|
||||||
activity.window,
|
activity.window,
|
||||||
@ -94,12 +95,3 @@ object ThemeHelper {
|
|||||||
windowController.isAppearanceLightNavigationBars = false
|
windowController.isAppearanceLightNavigationBars = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Theme(val int: Int) {
|
|
||||||
Default(0),
|
|
||||||
MaterialYou(1);
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun from(int: Int): Theme = entries.firstOrNull { it.int == int } ?: Default
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
|
|
||||||
#include "common/string_util.h"
|
#include "common/string_util.h"
|
||||||
#include "jni/id_cache.h"
|
|
||||||
|
|
||||||
std::string GetJString(JNIEnv* env, jstring jstr) {
|
std::string GetJString(JNIEnv* env, jstring jstr) {
|
||||||
if (!jstr) {
|
if (!jstr) {
|
||||||
@ -34,11 +33,3 @@ jstring ToJString(JNIEnv* env, std::string_view str) {
|
|||||||
jstring ToJString(JNIEnv* env, std::u16string_view str) {
|
jstring ToJString(JNIEnv* env, std::u16string_view str) {
|
||||||
return ToJString(env, Common::UTF16ToUTF8(str));
|
return ToJString(env, Common::UTF16ToUTF8(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
double GetJDouble(JNIEnv* env, jobject jdouble) {
|
|
||||||
return env->GetDoubleField(jdouble, IDCache::GetDoubleValueField());
|
|
||||||
}
|
|
||||||
|
|
||||||
jobject ToJDouble(JNIEnv* env, double value) {
|
|
||||||
return env->NewObject(IDCache::GetDoubleClass(), IDCache::GetDoubleConstructor(), value);
|
|
||||||
}
|
|
||||||
|
@ -10,6 +10,3 @@
|
|||||||
std::string GetJString(JNIEnv* env, jstring jstr);
|
std::string GetJString(JNIEnv* env, jstring jstr);
|
||||||
jstring ToJString(JNIEnv* env, std::string_view str);
|
jstring ToJString(JNIEnv* env, std::string_view str);
|
||||||
jstring ToJString(JNIEnv* env, std::u16string_view str);
|
jstring ToJString(JNIEnv* env, std::u16string_view str);
|
||||||
|
|
||||||
double GetJDouble(JNIEnv* env, jobject jdouble);
|
|
||||||
jobject ToJDouble(JNIEnv* env, double value);
|
|
||||||
|
@ -35,7 +35,6 @@ void AndroidConfig::ReadAndroidValues() {
|
|||||||
if (global) {
|
if (global) {
|
||||||
ReadAndroidUIValues();
|
ReadAndroidUIValues();
|
||||||
ReadUIValues();
|
ReadUIValues();
|
||||||
ReadOverlayValues();
|
|
||||||
}
|
}
|
||||||
ReadDriverValues();
|
ReadDriverValues();
|
||||||
}
|
}
|
||||||
@ -82,42 +81,10 @@ void AndroidConfig::ReadDriverValues() {
|
|||||||
EndGroup();
|
EndGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidConfig::ReadOverlayValues() {
|
|
||||||
BeginGroup(Settings::TranslateCategory(Settings::Category::Overlay));
|
|
||||||
|
|
||||||
ReadCategory(Settings::Category::Overlay);
|
|
||||||
|
|
||||||
AndroidSettings::values.overlay_control_data.clear();
|
|
||||||
const int control_data_size = BeginArray("control_data");
|
|
||||||
for (int i = 0; i < control_data_size; ++i) {
|
|
||||||
SetArrayIndex(i);
|
|
||||||
AndroidSettings::OverlayControlData control_data;
|
|
||||||
control_data.id = ReadStringSetting(std::string("id"));
|
|
||||||
control_data.enabled = ReadBooleanSetting(std::string("enabled"));
|
|
||||||
control_data.landscape_position.first =
|
|
||||||
ReadDoubleSetting(std::string("landscape\\x_position"));
|
|
||||||
control_data.landscape_position.second =
|
|
||||||
ReadDoubleSetting(std::string("landscape\\y_position"));
|
|
||||||
control_data.portrait_position.first =
|
|
||||||
ReadDoubleSetting(std::string("portrait\\x_position"));
|
|
||||||
control_data.portrait_position.second =
|
|
||||||
ReadDoubleSetting(std::string("portrait\\y_position"));
|
|
||||||
control_data.foldable_position.first =
|
|
||||||
ReadDoubleSetting(std::string("foldable\\x_position"));
|
|
||||||
control_data.foldable_position.second =
|
|
||||||
ReadDoubleSetting(std::string("foldable\\y_position"));
|
|
||||||
AndroidSettings::values.overlay_control_data.push_back(control_data);
|
|
||||||
}
|
|
||||||
EndArray();
|
|
||||||
|
|
||||||
EndGroup();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AndroidConfig::SaveAndroidValues() {
|
void AndroidConfig::SaveAndroidValues() {
|
||||||
if (global) {
|
if (global) {
|
||||||
SaveAndroidUIValues();
|
SaveAndroidUIValues();
|
||||||
SaveUIValues();
|
SaveUIValues();
|
||||||
SaveOverlayValues();
|
|
||||||
}
|
}
|
||||||
SaveDriverValues();
|
SaveDriverValues();
|
||||||
|
|
||||||
@ -147,9 +114,8 @@ void AndroidConfig::SavePathValues() {
|
|||||||
for (size_t i = 0; i < AndroidSettings::values.game_dirs.size(); ++i) {
|
for (size_t i = 0; i < AndroidSettings::values.game_dirs.size(); ++i) {
|
||||||
SetArrayIndex(i);
|
SetArrayIndex(i);
|
||||||
const auto& game_dir = AndroidSettings::values.game_dirs[i];
|
const auto& game_dir = AndroidSettings::values.game_dirs[i];
|
||||||
WriteStringSetting(std::string("path"), game_dir.path);
|
WriteSetting(std::string("path"), game_dir.path);
|
||||||
WriteBooleanSetting(std::string("deep_scan"), game_dir.deep_scan,
|
WriteSetting(std::string("deep_scan"), game_dir.deep_scan, std::make_optional(false));
|
||||||
std::make_optional(false));
|
|
||||||
}
|
}
|
||||||
EndArray();
|
EndArray();
|
||||||
|
|
||||||
@ -164,35 +130,6 @@ void AndroidConfig::SaveDriverValues() {
|
|||||||
EndGroup();
|
EndGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidConfig::SaveOverlayValues() {
|
|
||||||
BeginGroup(Settings::TranslateCategory(Settings::Category::Overlay));
|
|
||||||
|
|
||||||
WriteCategory(Settings::Category::Overlay);
|
|
||||||
|
|
||||||
BeginArray("control_data");
|
|
||||||
for (size_t i = 0; i < AndroidSettings::values.overlay_control_data.size(); ++i) {
|
|
||||||
SetArrayIndex(i);
|
|
||||||
const auto& control_data = AndroidSettings::values.overlay_control_data[i];
|
|
||||||
WriteStringSetting(std::string("id"), control_data.id);
|
|
||||||
WriteBooleanSetting(std::string("enabled"), control_data.enabled);
|
|
||||||
WriteDoubleSetting(std::string("landscape\\x_position"),
|
|
||||||
control_data.landscape_position.first);
|
|
||||||
WriteDoubleSetting(std::string("landscape\\y_position"),
|
|
||||||
control_data.landscape_position.second);
|
|
||||||
WriteDoubleSetting(std::string("portrait\\x_position"),
|
|
||||||
control_data.portrait_position.first);
|
|
||||||
WriteDoubleSetting(std::string("portrait\\y_position"),
|
|
||||||
control_data.portrait_position.second);
|
|
||||||
WriteDoubleSetting(std::string("foldable\\x_position"),
|
|
||||||
control_data.foldable_position.first);
|
|
||||||
WriteDoubleSetting(std::string("foldable\\y_position"),
|
|
||||||
control_data.foldable_position.second);
|
|
||||||
}
|
|
||||||
EndArray();
|
|
||||||
|
|
||||||
EndGroup();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Settings::BasicSetting*>& AndroidConfig::FindRelevantList(Settings::Category category) {
|
std::vector<Settings::BasicSetting*>& AndroidConfig::FindRelevantList(Settings::Category category) {
|
||||||
auto& map = Settings::values.linkage.by_category;
|
auto& map = Settings::values.linkage.by_category;
|
||||||
if (map.contains(category)) {
|
if (map.contains(category)) {
|
||||||
|
@ -18,7 +18,6 @@ protected:
|
|||||||
void ReadAndroidValues();
|
void ReadAndroidValues();
|
||||||
void ReadAndroidUIValues();
|
void ReadAndroidUIValues();
|
||||||
void ReadDriverValues();
|
void ReadDriverValues();
|
||||||
void ReadOverlayValues();
|
|
||||||
void ReadHidbusValues() override {}
|
void ReadHidbusValues() override {}
|
||||||
void ReadDebugControlValues() override {}
|
void ReadDebugControlValues() override {}
|
||||||
void ReadPathValues() override;
|
void ReadPathValues() override;
|
||||||
@ -31,7 +30,6 @@ protected:
|
|||||||
void SaveAndroidValues();
|
void SaveAndroidValues();
|
||||||
void SaveAndroidUIValues();
|
void SaveAndroidUIValues();
|
||||||
void SaveDriverValues();
|
void SaveDriverValues();
|
||||||
void SaveOverlayValues();
|
|
||||||
void SaveHidbusValues() override {}
|
void SaveHidbusValues() override {}
|
||||||
void SaveDebugControlValues() override {}
|
void SaveDebugControlValues() override {}
|
||||||
void SavePathValues() override;
|
void SavePathValues() override;
|
||||||
|
@ -14,14 +14,6 @@ struct GameDir {
|
|||||||
bool deep_scan = false;
|
bool deep_scan = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OverlayControlData {
|
|
||||||
std::string id;
|
|
||||||
bool enabled;
|
|
||||||
std::pair<double, double> landscape_position;
|
|
||||||
std::pair<double, double> portrait_position;
|
|
||||||
std::pair<double, double> foldable_position;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Values {
|
struct Values {
|
||||||
Settings::Linkage linkage;
|
Settings::Linkage linkage;
|
||||||
|
|
||||||
@ -41,28 +33,6 @@ struct Values {
|
|||||||
|
|
||||||
Settings::SwitchableSetting<std::string, false> driver_path{linkage, "", "driver_path",
|
Settings::SwitchableSetting<std::string, false> driver_path{linkage, "", "driver_path",
|
||||||
Settings::Category::GpuDriver};
|
Settings::Category::GpuDriver};
|
||||||
|
|
||||||
Settings::Setting<s32> theme{linkage, 0, "theme", Settings::Category::Android};
|
|
||||||
Settings::Setting<s32> theme_mode{linkage, -1, "theme_mode", Settings::Category::Android};
|
|
||||||
Settings::Setting<bool> black_backgrounds{linkage, false, "black_backgrounds",
|
|
||||||
Settings::Category::Android};
|
|
||||||
|
|
||||||
// Input/performance overlay settings
|
|
||||||
std::vector<OverlayControlData> overlay_control_data;
|
|
||||||
Settings::Setting<s32> overlay_scale{linkage, 50, "control_scale", Settings::Category::Overlay};
|
|
||||||
Settings::Setting<s32> overlay_opacity{linkage, 100, "control_opacity",
|
|
||||||
Settings::Category::Overlay};
|
|
||||||
|
|
||||||
Settings::Setting<bool> joystick_rel_center{linkage, true, "joystick_rel_center",
|
|
||||||
Settings::Category::Overlay};
|
|
||||||
Settings::Setting<bool> dpad_slide{linkage, true, "dpad_slide", Settings::Category::Overlay};
|
|
||||||
Settings::Setting<bool> haptic_feedback{linkage, true, "haptic_feedback",
|
|
||||||
Settings::Category::Overlay};
|
|
||||||
Settings::Setting<bool> show_performance_overlay{linkage, true, "show_performance_overlay",
|
|
||||||
Settings::Category::Overlay};
|
|
||||||
Settings::Setting<bool> show_input_overlay{linkage, true, "show_input_overlay",
|
|
||||||
Settings::Category::Overlay};
|
|
||||||
Settings::Setting<bool> touchscreen{linkage, true, "touchscreen", Settings::Category::Overlay};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Values values;
|
extern Values values;
|
||||||
|
@ -35,18 +35,6 @@ static jmethodID s_pair_constructor;
|
|||||||
static jfieldID s_pair_first_field;
|
static jfieldID s_pair_first_field;
|
||||||
static jfieldID s_pair_second_field;
|
static jfieldID s_pair_second_field;
|
||||||
|
|
||||||
static jclass s_overlay_control_data_class;
|
|
||||||
static jmethodID s_overlay_control_data_constructor;
|
|
||||||
static jfieldID s_overlay_control_data_id_field;
|
|
||||||
static jfieldID s_overlay_control_data_enabled_field;
|
|
||||||
static jfieldID s_overlay_control_data_landscape_position_field;
|
|
||||||
static jfieldID s_overlay_control_data_portrait_position_field;
|
|
||||||
static jfieldID s_overlay_control_data_foldable_position_field;
|
|
||||||
|
|
||||||
static jclass s_double_class;
|
|
||||||
static jmethodID s_double_constructor;
|
|
||||||
static jfieldID s_double_value_field;
|
|
||||||
|
|
||||||
static constexpr jint JNI_VERSION = JNI_VERSION_1_6;
|
static constexpr jint JNI_VERSION = JNI_VERSION_1_6;
|
||||||
|
|
||||||
namespace IDCache {
|
namespace IDCache {
|
||||||
@ -158,46 +146,6 @@ jfieldID GetPairSecondField() {
|
|||||||
return s_pair_second_field;
|
return s_pair_second_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jclass GetOverlayControlDataClass() {
|
|
||||||
return s_overlay_control_data_class;
|
|
||||||
}
|
|
||||||
|
|
||||||
jmethodID GetOverlayControlDataConstructor() {
|
|
||||||
return s_overlay_control_data_constructor;
|
|
||||||
}
|
|
||||||
|
|
||||||
jfieldID GetOverlayControlDataIdField() {
|
|
||||||
return s_overlay_control_data_id_field;
|
|
||||||
}
|
|
||||||
|
|
||||||
jfieldID GetOverlayControlDataEnabledField() {
|
|
||||||
return s_overlay_control_data_enabled_field;
|
|
||||||
}
|
|
||||||
|
|
||||||
jfieldID GetOverlayControlDataLandscapePositionField() {
|
|
||||||
return s_overlay_control_data_landscape_position_field;
|
|
||||||
}
|
|
||||||
|
|
||||||
jfieldID GetOverlayControlDataPortraitPositionField() {
|
|
||||||
return s_overlay_control_data_portrait_position_field;
|
|
||||||
}
|
|
||||||
|
|
||||||
jfieldID GetOverlayControlDataFoldablePositionField() {
|
|
||||||
return s_overlay_control_data_foldable_position_field;
|
|
||||||
}
|
|
||||||
|
|
||||||
jclass GetDoubleClass() {
|
|
||||||
return s_double_class;
|
|
||||||
}
|
|
||||||
|
|
||||||
jmethodID GetDoubleConstructor() {
|
|
||||||
return s_double_constructor;
|
|
||||||
}
|
|
||||||
|
|
||||||
jfieldID GetDoubleValueField() {
|
|
||||||
return s_double_value_field;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace IDCache
|
} // namespace IDCache
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@ -259,31 +207,6 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
|||||||
s_pair_second_field = env->GetFieldID(pair_class, "second", "Ljava/lang/Object;");
|
s_pair_second_field = env->GetFieldID(pair_class, "second", "Ljava/lang/Object;");
|
||||||
env->DeleteLocalRef(pair_class);
|
env->DeleteLocalRef(pair_class);
|
||||||
|
|
||||||
const jclass overlay_control_data_class =
|
|
||||||
env->FindClass("org/yuzu/yuzu_emu/overlay/model/OverlayControlData");
|
|
||||||
s_overlay_control_data_class =
|
|
||||||
reinterpret_cast<jclass>(env->NewGlobalRef(overlay_control_data_class));
|
|
||||||
s_overlay_control_data_constructor =
|
|
||||||
env->GetMethodID(overlay_control_data_class, "<init>",
|
|
||||||
"(Ljava/lang/String;ZLkotlin/Pair;Lkotlin/Pair;Lkotlin/Pair;)V");
|
|
||||||
s_overlay_control_data_id_field =
|
|
||||||
env->GetFieldID(overlay_control_data_class, "id", "Ljava/lang/String;");
|
|
||||||
s_overlay_control_data_enabled_field =
|
|
||||||
env->GetFieldID(overlay_control_data_class, "enabled", "Z");
|
|
||||||
s_overlay_control_data_landscape_position_field =
|
|
||||||
env->GetFieldID(overlay_control_data_class, "landscapePosition", "Lkotlin/Pair;");
|
|
||||||
s_overlay_control_data_portrait_position_field =
|
|
||||||
env->GetFieldID(overlay_control_data_class, "portraitPosition", "Lkotlin/Pair;");
|
|
||||||
s_overlay_control_data_foldable_position_field =
|
|
||||||
env->GetFieldID(overlay_control_data_class, "foldablePosition", "Lkotlin/Pair;");
|
|
||||||
env->DeleteLocalRef(overlay_control_data_class);
|
|
||||||
|
|
||||||
const jclass double_class = env->FindClass("java/lang/Double");
|
|
||||||
s_double_class = reinterpret_cast<jclass>(env->NewGlobalRef(double_class));
|
|
||||||
s_double_constructor = env->GetMethodID(double_class, "<init>", "(D)V");
|
|
||||||
s_double_value_field = env->GetFieldID(double_class, "value", "D");
|
|
||||||
env->DeleteLocalRef(double_class);
|
|
||||||
|
|
||||||
// Initialize Android Storage
|
// Initialize Android Storage
|
||||||
Common::FS::Android::RegisterCallbacks(env, s_native_library_class);
|
Common::FS::Android::RegisterCallbacks(env, s_native_library_class);
|
||||||
|
|
||||||
@ -308,8 +231,6 @@ void JNI_OnUnload(JavaVM* vm, void* reserved) {
|
|||||||
env->DeleteGlobalRef(s_game_class);
|
env->DeleteGlobalRef(s_game_class);
|
||||||
env->DeleteGlobalRef(s_string_class);
|
env->DeleteGlobalRef(s_string_class);
|
||||||
env->DeleteGlobalRef(s_pair_class);
|
env->DeleteGlobalRef(s_pair_class);
|
||||||
env->DeleteGlobalRef(s_overlay_control_data_class);
|
|
||||||
env->DeleteGlobalRef(s_double_class);
|
|
||||||
|
|
||||||
// UnInitialize applets
|
// UnInitialize applets
|
||||||
SoftwareKeyboard::CleanupJNI(env);
|
SoftwareKeyboard::CleanupJNI(env);
|
||||||
|
@ -35,16 +35,4 @@ jmethodID GetPairConstructor();
|
|||||||
jfieldID GetPairFirstField();
|
jfieldID GetPairFirstField();
|
||||||
jfieldID GetPairSecondField();
|
jfieldID GetPairSecondField();
|
||||||
|
|
||||||
jclass GetOverlayControlDataClass();
|
|
||||||
jmethodID GetOverlayControlDataConstructor();
|
|
||||||
jfieldID GetOverlayControlDataIdField();
|
|
||||||
jfieldID GetOverlayControlDataEnabledField();
|
|
||||||
jfieldID GetOverlayControlDataLandscapePositionField();
|
|
||||||
jfieldID GetOverlayControlDataPortraitPositionField();
|
|
||||||
jfieldID GetOverlayControlDataFoldablePositionField();
|
|
||||||
|
|
||||||
jclass GetDoubleClass();
|
|
||||||
jmethodID GetDoubleConstructor();
|
|
||||||
jfieldID GetDoubleValueField();
|
|
||||||
|
|
||||||
} // namespace IDCache
|
} // namespace IDCache
|
||||||
|
@ -344,74 +344,4 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setDisabledAddons(JNIEnv* env, j
|
|||||||
Settings::values.disabled_addons[program_id] = disabled_addons;
|
Settings::values.disabled_addons[program_id] = disabled_addons;
|
||||||
}
|
}
|
||||||
|
|
||||||
jobjectArray Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getOverlayControlData(JNIEnv* env,
|
|
||||||
jobject obj) {
|
|
||||||
jobjectArray joverlayControlDataArray =
|
|
||||||
env->NewObjectArray(AndroidSettings::values.overlay_control_data.size(),
|
|
||||||
IDCache::GetOverlayControlDataClass(), nullptr);
|
|
||||||
for (size_t i = 0; i < AndroidSettings::values.overlay_control_data.size(); ++i) {
|
|
||||||
const auto& control_data = AndroidSettings::values.overlay_control_data[i];
|
|
||||||
jobject jlandscapePosition =
|
|
||||||
env->NewObject(IDCache::GetPairClass(), IDCache::GetPairConstructor(),
|
|
||||||
ToJDouble(env, control_data.landscape_position.first),
|
|
||||||
ToJDouble(env, control_data.landscape_position.second));
|
|
||||||
jobject jportraitPosition =
|
|
||||||
env->NewObject(IDCache::GetPairClass(), IDCache::GetPairConstructor(),
|
|
||||||
ToJDouble(env, control_data.portrait_position.first),
|
|
||||||
ToJDouble(env, control_data.portrait_position.second));
|
|
||||||
jobject jfoldablePosition =
|
|
||||||
env->NewObject(IDCache::GetPairClass(), IDCache::GetPairConstructor(),
|
|
||||||
ToJDouble(env, control_data.foldable_position.first),
|
|
||||||
ToJDouble(env, control_data.foldable_position.second));
|
|
||||||
|
|
||||||
jobject jcontrolData = env->NewObject(
|
|
||||||
IDCache::GetOverlayControlDataClass(), IDCache::GetOverlayControlDataConstructor(),
|
|
||||||
ToJString(env, control_data.id), control_data.enabled, jlandscapePosition,
|
|
||||||
jportraitPosition, jfoldablePosition);
|
|
||||||
env->SetObjectArrayElement(joverlayControlDataArray, i, jcontrolData);
|
|
||||||
}
|
|
||||||
return joverlayControlDataArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setOverlayControlData(
|
|
||||||
JNIEnv* env, jobject obj, jobjectArray joverlayControlDataArray) {
|
|
||||||
AndroidSettings::values.overlay_control_data.clear();
|
|
||||||
int size = env->GetArrayLength(joverlayControlDataArray);
|
|
||||||
|
|
||||||
if (size == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < size; ++i) {
|
|
||||||
jobject joverlayControlData = env->GetObjectArrayElement(joverlayControlDataArray, i);
|
|
||||||
jstring jidString = static_cast<jstring>(
|
|
||||||
env->GetObjectField(joverlayControlData, IDCache::GetOverlayControlDataIdField()));
|
|
||||||
bool enabled = static_cast<bool>(env->GetBooleanField(
|
|
||||||
joverlayControlData, IDCache::GetOverlayControlDataEnabledField()));
|
|
||||||
|
|
||||||
jobject jlandscapePosition = env->GetObjectField(
|
|
||||||
joverlayControlData, IDCache::GetOverlayControlDataLandscapePositionField());
|
|
||||||
std::pair<double, double> landscape_position = std::make_pair(
|
|
||||||
GetJDouble(env, env->GetObjectField(jlandscapePosition, IDCache::GetPairFirstField())),
|
|
||||||
GetJDouble(env,
|
|
||||||
env->GetObjectField(jlandscapePosition, IDCache::GetPairSecondField())));
|
|
||||||
|
|
||||||
jobject jportraitPosition = env->GetObjectField(
|
|
||||||
joverlayControlData, IDCache::GetOverlayControlDataPortraitPositionField());
|
|
||||||
std::pair<double, double> portrait_position = std::make_pair(
|
|
||||||
GetJDouble(env, env->GetObjectField(jportraitPosition, IDCache::GetPairFirstField())),
|
|
||||||
GetJDouble(env, env->GetObjectField(jportraitPosition, IDCache::GetPairSecondField())));
|
|
||||||
|
|
||||||
jobject jfoldablePosition = env->GetObjectField(
|
|
||||||
joverlayControlData, IDCache::GetOverlayControlDataFoldablePositionField());
|
|
||||||
std::pair<double, double> foldable_position = std::make_pair(
|
|
||||||
GetJDouble(env, env->GetObjectField(jfoldablePosition, IDCache::GetPairFirstField())),
|
|
||||||
GetJDouble(env, env->GetObjectField(jfoldablePosition, IDCache::GetPairSecondField())));
|
|
||||||
|
|
||||||
AndroidSettings::values.overlay_control_data.push_back(AndroidSettings::OverlayControlData{
|
|
||||||
GetJString(env, jidString), enabled, landscape_position, portrait_position,
|
|
||||||
foldable_position});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="24dp"
|
android:layout_marginEnd="24dp"
|
||||||
android:layout_gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:layout_weight="1">
|
android:layout_weight="1">
|
||||||
|
|
||||||
|
@ -38,11 +38,6 @@
|
|||||||
android:title="@string/emulation_haptics"
|
android:title="@string/emulation_haptics"
|
||||||
android:checkable="true" />
|
android:checkable="true" />
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/menu_touchscreen"
|
|
||||||
android:title="@string/touchscreen"
|
|
||||||
android:checkable="true" />
|
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/menu_reset_overlay"
|
android:id="@+id/menu_reset_overlay"
|
||||||
android:title="@string/emulation_touch_overlay_reset" />
|
android:title="@string/emulation_touch_overlay_reset" />
|
||||||
|
@ -212,19 +212,19 @@
|
|||||||
<item>B</item>
|
<item>B</item>
|
||||||
<item>X</item>
|
<item>X</item>
|
||||||
<item>Y</item>
|
<item>Y</item>
|
||||||
<item>+</item>
|
|
||||||
<item>-</item>
|
|
||||||
<item>@string/gamepad_home</item>
|
|
||||||
<item>@string/gamepad_screenshot</item>
|
|
||||||
<item>L</item>
|
<item>L</item>
|
||||||
<item>R</item>
|
<item>R</item>
|
||||||
<item>ZL</item>
|
<item>ZL</item>
|
||||||
<item>ZR</item>
|
<item>ZR</item>
|
||||||
|
<item>+</item>
|
||||||
|
<item>-</item>
|
||||||
|
<item>@string/gamepad_d_pad</item>
|
||||||
<item>@string/gamepad_left_stick</item>
|
<item>@string/gamepad_left_stick</item>
|
||||||
<item>@string/gamepad_right_stick</item>
|
<item>@string/gamepad_right_stick</item>
|
||||||
<item>L3</item>
|
<item>L3</item>
|
||||||
<item>R3</item>
|
<item>R3</item>
|
||||||
<item>@string/gamepad_d_pad</item>
|
<item>@string/gamepad_home</item>
|
||||||
|
<item>@string/gamepad_screenshot</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<string-array name="themeEntries">
|
<string-array name="themeEntries">
|
||||||
@ -267,21 +267,4 @@
|
|||||||
<item>3</item>
|
<item>3</item>
|
||||||
</integer-array>
|
</integer-array>
|
||||||
|
|
||||||
<string-array name="anisoEntries">
|
|
||||||
<item>@string/auto</item>
|
|
||||||
<item>@string/slider_default</item>
|
|
||||||
<item>@string/multiplier_two</item>
|
|
||||||
<item>@string/multiplier_four</item>
|
|
||||||
<item>@string/multiplier_eight</item>
|
|
||||||
<item>@string/multiplier_sixteen</item>
|
|
||||||
</string-array>
|
|
||||||
<integer-array name="anisoValues">
|
|
||||||
<item>0</item>
|
|
||||||
<item>1</item>
|
|
||||||
<item>2</item>
|
|
||||||
<item>3</item>
|
|
||||||
<item>4</item>
|
|
||||||
<item>5</item>
|
|
||||||
</integer-array>
|
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -3,111 +3,111 @@
|
|||||||
<integer name="grid_columns">1</integer>
|
<integer name="grid_columns">1</integer>
|
||||||
|
|
||||||
<!-- Default SWITCH landscape layout -->
|
<!-- Default SWITCH landscape layout -->
|
||||||
<integer name="BUTTON_A_X">760</integer>
|
<integer name="SWITCH_BUTTON_A_X">760</integer>
|
||||||
<integer name="BUTTON_A_Y">790</integer>
|
<integer name="SWITCH_BUTTON_A_Y">790</integer>
|
||||||
<integer name="BUTTON_B_X">710</integer>
|
<integer name="SWITCH_BUTTON_B_X">710</integer>
|
||||||
<integer name="BUTTON_B_Y">900</integer>
|
<integer name="SWITCH_BUTTON_B_Y">900</integer>
|
||||||
<integer name="BUTTON_X_X">710</integer>
|
<integer name="SWITCH_BUTTON_X_X">710</integer>
|
||||||
<integer name="BUTTON_X_Y">680</integer>
|
<integer name="SWITCH_BUTTON_X_Y">680</integer>
|
||||||
<integer name="BUTTON_Y_X">660</integer>
|
<integer name="SWITCH_BUTTON_Y_X">660</integer>
|
||||||
<integer name="BUTTON_Y_Y">790</integer>
|
<integer name="SWITCH_BUTTON_Y_Y">790</integer>
|
||||||
<integer name="BUTTON_PLUS_X">540</integer>
|
<integer name="SWITCH_STICK_L_X">100</integer>
|
||||||
<integer name="BUTTON_PLUS_Y">950</integer>
|
<integer name="SWITCH_STICK_L_Y">670</integer>
|
||||||
<integer name="BUTTON_MINUS_X">460</integer>
|
<integer name="SWITCH_STICK_R_X">900</integer>
|
||||||
<integer name="BUTTON_MINUS_Y">950</integer>
|
<integer name="SWITCH_STICK_R_Y">670</integer>
|
||||||
<integer name="BUTTON_HOME_X">600</integer>
|
<integer name="SWITCH_TRIGGER_L_X">70</integer>
|
||||||
<integer name="BUTTON_HOME_Y">950</integer>
|
<integer name="SWITCH_TRIGGER_L_Y">220</integer>
|
||||||
<integer name="BUTTON_CAPTURE_X">400</integer>
|
<integer name="SWITCH_TRIGGER_R_X">930</integer>
|
||||||
<integer name="BUTTON_CAPTURE_Y">950</integer>
|
<integer name="SWITCH_TRIGGER_R_Y">220</integer>
|
||||||
<integer name="BUTTON_L_X">70</integer>
|
<integer name="SWITCH_TRIGGER_ZL_X">70</integer>
|
||||||
<integer name="BUTTON_L_Y">220</integer>
|
<integer name="SWITCH_TRIGGER_ZL_Y">90</integer>
|
||||||
<integer name="BUTTON_R_X">930</integer>
|
<integer name="SWITCH_TRIGGER_ZR_X">930</integer>
|
||||||
<integer name="BUTTON_R_Y">220</integer>
|
<integer name="SWITCH_TRIGGER_ZR_Y">90</integer>
|
||||||
<integer name="BUTTON_ZL_X">70</integer>
|
<integer name="SWITCH_BUTTON_MINUS_X">460</integer>
|
||||||
<integer name="BUTTON_ZL_Y">90</integer>
|
<integer name="SWITCH_BUTTON_MINUS_Y">950</integer>
|
||||||
<integer name="BUTTON_ZR_X">930</integer>
|
<integer name="SWITCH_BUTTON_PLUS_X">540</integer>
|
||||||
<integer name="BUTTON_ZR_Y">90</integer>
|
<integer name="SWITCH_BUTTON_PLUS_Y">950</integer>
|
||||||
<integer name="BUTTON_STICK_L_X">870</integer>
|
<integer name="SWITCH_BUTTON_HOME_X">600</integer>
|
||||||
<integer name="BUTTON_STICK_L_Y">400</integer>
|
<integer name="SWITCH_BUTTON_HOME_Y">950</integer>
|
||||||
<integer name="BUTTON_STICK_R_X">960</integer>
|
<integer name="SWITCH_BUTTON_CAPTURE_X">400</integer>
|
||||||
<integer name="BUTTON_STICK_R_Y">430</integer>
|
<integer name="SWITCH_BUTTON_CAPTURE_Y">950</integer>
|
||||||
<integer name="STICK_L_X">100</integer>
|
<integer name="SWITCH_BUTTON_DPAD_X">260</integer>
|
||||||
<integer name="STICK_L_Y">670</integer>
|
<integer name="SWITCH_BUTTON_DPAD_Y">790</integer>
|
||||||
<integer name="STICK_R_X">900</integer>
|
<integer name="SWITCH_BUTTON_STICK_L_X">870</integer>
|
||||||
<integer name="STICK_R_Y">670</integer>
|
<integer name="SWITCH_BUTTON_STICK_L_Y">400</integer>
|
||||||
<integer name="COMBINED_DPAD_X">260</integer>
|
<integer name="SWITCH_BUTTON_STICK_R_X">960</integer>
|
||||||
<integer name="COMBINED_DPAD_Y">790</integer>
|
<integer name="SWITCH_BUTTON_STICK_R_Y">430</integer>
|
||||||
|
|
||||||
<!-- Default SWITCH portrait layout -->
|
<!-- Default SWITCH portrait layout -->
|
||||||
<integer name="BUTTON_A_X_PORTRAIT">840</integer>
|
<integer name="SWITCH_BUTTON_A_X_PORTRAIT">840</integer>
|
||||||
<integer name="BUTTON_A_Y_PORTRAIT">840</integer>
|
<integer name="SWITCH_BUTTON_A_Y_PORTRAIT">840</integer>
|
||||||
<integer name="BUTTON_B_X_PORTRAIT">740</integer>
|
<integer name="SWITCH_BUTTON_B_X_PORTRAIT">740</integer>
|
||||||
<integer name="BUTTON_B_Y_PORTRAIT">880</integer>
|
<integer name="SWITCH_BUTTON_B_Y_PORTRAIT">880</integer>
|
||||||
<integer name="BUTTON_X_X_PORTRAIT">740</integer>
|
<integer name="SWITCH_BUTTON_X_X_PORTRAIT">740</integer>
|
||||||
<integer name="BUTTON_X_Y_PORTRAIT">800</integer>
|
<integer name="SWITCH_BUTTON_X_Y_PORTRAIT">800</integer>
|
||||||
<integer name="BUTTON_Y_X_PORTRAIT">640</integer>
|
<integer name="SWITCH_BUTTON_Y_X_PORTRAIT">640</integer>
|
||||||
<integer name="BUTTON_Y_Y_PORTRAIT">840</integer>
|
<integer name="SWITCH_BUTTON_Y_Y_PORTRAIT">840</integer>
|
||||||
<integer name="BUTTON_PLUS_Y_PORTRAIT">950</integer>
|
<integer name="SWITCH_STICK_L_X_PORTRAIT">180</integer>
|
||||||
<integer name="BUTTON_MINUS_X_PORTRAIT">440</integer>
|
<integer name="SWITCH_STICK_L_Y_PORTRAIT">660</integer>
|
||||||
<integer name="BUTTON_MINUS_Y_PORTRAIT">950</integer>
|
<integer name="SWITCH_STICK_R_X_PORTRAIT">820</integer>
|
||||||
<integer name="BUTTON_HOME_X_PORTRAIT">680</integer>
|
<integer name="SWITCH_STICK_R_Y_PORTRAIT">660</integer>
|
||||||
<integer name="BUTTON_HOME_Y_PORTRAIT">950</integer>
|
<integer name="SWITCH_TRIGGER_L_X_PORTRAIT">140</integer>
|
||||||
<integer name="BUTTON_CAPTURE_X_PORTRAIT">320</integer>
|
<integer name="SWITCH_TRIGGER_L_Y_PORTRAIT">260</integer>
|
||||||
<integer name="BUTTON_CAPTURE_Y_PORTRAIT">950</integer>
|
<integer name="SWITCH_TRIGGER_R_X_PORTRAIT">860</integer>
|
||||||
<integer name="BUTTON_L_X_PORTRAIT">140</integer>
|
<integer name="SWITCH_TRIGGER_R_Y_PORTRAIT">260</integer>
|
||||||
<integer name="BUTTON_L_Y_PORTRAIT">260</integer>
|
<integer name="SWITCH_TRIGGER_ZL_X_PORTRAIT">140</integer>
|
||||||
<integer name="BUTTON_R_X_PORTRAIT">860</integer>
|
<integer name="SWITCH_TRIGGER_ZL_Y_PORTRAIT">200</integer>
|
||||||
<integer name="BUTTON_R_Y_PORTRAIT">260</integer>
|
<integer name="SWITCH_TRIGGER_ZR_X_PORTRAIT">860</integer>
|
||||||
<integer name="BUTTON_ZL_X_PORTRAIT">140</integer>
|
<integer name="SWITCH_TRIGGER_ZR_Y_PORTRAIT">200</integer>
|
||||||
<integer name="BUTTON_ZL_Y_PORTRAIT">200</integer>
|
<integer name="SWITCH_BUTTON_MINUS_X_PORTRAIT">440</integer>
|
||||||
<integer name="BUTTON_ZR_X_PORTRAIT">860</integer>
|
<integer name="SWITCH_BUTTON_MINUS_Y_PORTRAIT">950</integer>
|
||||||
<integer name="BUTTON_ZR_Y_PORTRAIT">200</integer>
|
<integer name="SWITCH_BUTTON_PLUS_X_PORTRAIT">560</integer>
|
||||||
<integer name="BUTTON_PLUS_X_PORTRAIT">560</integer>
|
<integer name="SWITCH_BUTTON_PLUS_Y_PORTRAIT">950</integer>
|
||||||
<integer name="BUTTON_STICK_L_X_PORTRAIT">730</integer>
|
<integer name="SWITCH_BUTTON_HOME_X_PORTRAIT">680</integer>
|
||||||
<integer name="BUTTON_STICK_L_Y_PORTRAIT">510</integer>
|
<integer name="SWITCH_BUTTON_HOME_Y_PORTRAIT">950</integer>
|
||||||
<integer name="BUTTON_STICK_R_X_PORTRAIT">900</integer>
|
<integer name="SWITCH_BUTTON_CAPTURE_X_PORTRAIT">320</integer>
|
||||||
<integer name="BUTTON_STICK_R_Y_PORTRAIT">540</integer>
|
<integer name="SWITCH_BUTTON_CAPTURE_Y_PORTRAIT">950</integer>
|
||||||
<integer name="STICK_L_X_PORTRAIT">180</integer>
|
<integer name="SWITCH_BUTTON_DPAD_X_PORTRAIT">240</integer>
|
||||||
<integer name="STICK_L_Y_PORTRAIT">660</integer>
|
<integer name="SWITCH_BUTTON_DPAD_Y_PORTRAIT">840</integer>
|
||||||
<integer name="STICK_R_X_PORTRAIT">820</integer>
|
<integer name="SWITCH_BUTTON_STICK_L_X_PORTRAIT">730</integer>
|
||||||
<integer name="STICK_R_Y_PORTRAIT">660</integer>
|
<integer name="SWITCH_BUTTON_STICK_L_Y_PORTRAIT">510</integer>
|
||||||
<integer name="COMBINED_DPAD_X_PORTRAIT">240</integer>
|
<integer name="SWITCH_BUTTON_STICK_R_X_PORTRAIT">900</integer>
|
||||||
<integer name="COMBINED_DPAD_Y_PORTRAIT">840</integer>
|
<integer name="SWITCH_BUTTON_STICK_R_Y_PORTRAIT">540</integer>
|
||||||
|
|
||||||
<!-- Default SWITCH foldable layout -->
|
<!-- Default SWITCH foldable layout -->
|
||||||
<integer name="BUTTON_A_X_FOLDABLE">840</integer>
|
<integer name="SWITCH_BUTTON_A_X_FOLDABLE">840</integer>
|
||||||
<integer name="BUTTON_A_Y_FOLDABLE">390</integer>
|
<integer name="SWITCH_BUTTON_A_Y_FOLDABLE">390</integer>
|
||||||
<integer name="BUTTON_B_X_FOLDABLE">740</integer>
|
<integer name="SWITCH_BUTTON_B_X_FOLDABLE">740</integer>
|
||||||
<integer name="BUTTON_B_Y_FOLDABLE">430</integer>
|
<integer name="SWITCH_BUTTON_B_Y_FOLDABLE">430</integer>
|
||||||
<integer name="BUTTON_X_X_FOLDABLE">740</integer>
|
<integer name="SWITCH_BUTTON_X_X_FOLDABLE">740</integer>
|
||||||
<integer name="BUTTON_X_Y_FOLDABLE">350</integer>
|
<integer name="SWITCH_BUTTON_X_Y_FOLDABLE">350</integer>
|
||||||
<integer name="BUTTON_Y_X_FOLDABLE">640</integer>
|
<integer name="SWITCH_BUTTON_Y_X_FOLDABLE">640</integer>
|
||||||
<integer name="BUTTON_Y_Y_FOLDABLE">390</integer>
|
<integer name="SWITCH_BUTTON_Y_Y_FOLDABLE">390</integer>
|
||||||
<integer name="BUTTON_PLUS_X_FOLDABLE">560</integer>
|
<integer name="SWITCH_STICK_L_X_FOLDABLE">180</integer>
|
||||||
<integer name="BUTTON_PLUS_Y_FOLDABLE">470</integer>
|
<integer name="SWITCH_STICK_L_Y_FOLDABLE">250</integer>
|
||||||
<integer name="BUTTON_MINUS_X_FOLDABLE">440</integer>
|
<integer name="SWITCH_STICK_R_X_FOLDABLE">820</integer>
|
||||||
<integer name="BUTTON_MINUS_Y_FOLDABLE">470</integer>
|
<integer name="SWITCH_STICK_R_Y_FOLDABLE">250</integer>
|
||||||
<integer name="BUTTON_HOME_X_FOLDABLE">680</integer>
|
<integer name="SWITCH_TRIGGER_L_X_FOLDABLE">140</integer>
|
||||||
<integer name="BUTTON_HOME_Y_FOLDABLE">470</integer>
|
<integer name="SWITCH_TRIGGER_L_Y_FOLDABLE">130</integer>
|
||||||
<integer name="BUTTON_CAPTURE_X_FOLDABLE">320</integer>
|
<integer name="SWITCH_TRIGGER_R_X_FOLDABLE">860</integer>
|
||||||
<integer name="BUTTON_CAPTURE_Y_FOLDABLE">470</integer>
|
<integer name="SWITCH_TRIGGER_R_Y_FOLDABLE">130</integer>
|
||||||
<integer name="BUTTON_L_X_FOLDABLE">140</integer>
|
<integer name="SWITCH_TRIGGER_ZL_X_FOLDABLE">140</integer>
|
||||||
<integer name="BUTTON_L_Y_FOLDABLE">130</integer>
|
<integer name="SWITCH_TRIGGER_ZL_Y_FOLDABLE">70</integer>
|
||||||
<integer name="BUTTON_R_X_FOLDABLE">860</integer>
|
<integer name="SWITCH_TRIGGER_ZR_X_FOLDABLE">860</integer>
|
||||||
<integer name="BUTTON_R_Y_FOLDABLE">130</integer>
|
<integer name="SWITCH_TRIGGER_ZR_Y_FOLDABLE">70</integer>
|
||||||
<integer name="BUTTON_ZL_X_FOLDABLE">140</integer>
|
<integer name="SWITCH_BUTTON_MINUS_X_FOLDABLE">440</integer>
|
||||||
<integer name="BUTTON_ZL_Y_FOLDABLE">70</integer>
|
<integer name="SWITCH_BUTTON_MINUS_Y_FOLDABLE">470</integer>
|
||||||
<integer name="BUTTON_ZR_X_FOLDABLE">860</integer>
|
<integer name="SWITCH_BUTTON_PLUS_X_FOLDABLE">560</integer>
|
||||||
<integer name="BUTTON_ZR_Y_FOLDABLE">70</integer>
|
<integer name="SWITCH_BUTTON_PLUS_Y_FOLDABLE">470</integer>
|
||||||
<integer name="BUTTON_STICK_L_X_FOLDABLE">550</integer>
|
<integer name="SWITCH_BUTTON_HOME_X_FOLDABLE">680</integer>
|
||||||
<integer name="BUTTON_STICK_L_Y_FOLDABLE">210</integer>
|
<integer name="SWITCH_BUTTON_HOME_Y_FOLDABLE">470</integer>
|
||||||
<integer name="BUTTON_STICK_R_X_FOLDABLE">550</integer>
|
<integer name="SWITCH_BUTTON_CAPTURE_X_FOLDABLE">320</integer>
|
||||||
<integer name="BUTTON_STICK_R_Y_FOLDABLE">280</integer>
|
<integer name="SWITCH_BUTTON_CAPTURE_Y_FOLDABLE">470</integer>
|
||||||
<integer name="STICK_L_X_FOLDABLE">180</integer>
|
<integer name="SWITCH_BUTTON_DPAD_X_FOLDABLE">240</integer>
|
||||||
<integer name="STICK_L_Y_FOLDABLE">250</integer>
|
<integer name="SWITCH_BUTTON_DPAD_Y_FOLDABLE">390</integer>
|
||||||
<integer name="STICK_R_X_FOLDABLE">820</integer>
|
<integer name="SWITCH_BUTTON_STICK_L_X_FOLDABLE">550</integer>
|
||||||
<integer name="STICK_R_Y_FOLDABLE">250</integer>
|
<integer name="SWITCH_BUTTON_STICK_L_Y_FOLDABLE">210</integer>
|
||||||
<integer name="COMBINED_DPAD_X_FOLDABLE">240</integer>
|
<integer name="SWITCH_BUTTON_STICK_R_X_FOLDABLE">550</integer>
|
||||||
<integer name="COMBINED_DPAD_Y_FOLDABLE">390</integer>
|
<integer name="SWITCH_BUTTON_STICK_R_Y_FOLDABLE">280</integer>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -225,8 +225,6 @@
|
|||||||
<string name="renderer_reactive_flushing_description">Improves rendering accuracy in some games at the cost of performance.</string>
|
<string name="renderer_reactive_flushing_description">Improves rendering accuracy in some games at the cost of performance.</string>
|
||||||
<string name="use_disk_shader_cache">Disk shader cache</string>
|
<string name="use_disk_shader_cache">Disk shader cache</string>
|
||||||
<string name="use_disk_shader_cache_description">Reduces stuttering by locally storing and loading generated shaders.</string>
|
<string name="use_disk_shader_cache_description">Reduces stuttering by locally storing and loading generated shaders.</string>
|
||||||
<string name="anisotropic_filtering">Anisotropic filtering</string>
|
|
||||||
<string name="anisotropic_filtering_description">Improves the quality of textures when viewed at oblique angles</string>
|
|
||||||
|
|
||||||
<!-- Debug settings strings -->
|
<!-- Debug settings strings -->
|
||||||
<string name="cpu">CPU</string>
|
<string name="cpu">CPU</string>
|
||||||
@ -366,7 +364,6 @@
|
|||||||
<string name="emulation_pause">Pause emulation</string>
|
<string name="emulation_pause">Pause emulation</string>
|
||||||
<string name="emulation_unpause">Unpause emulation</string>
|
<string name="emulation_unpause">Unpause emulation</string>
|
||||||
<string name="emulation_input_overlay">Overlay options</string>
|
<string name="emulation_input_overlay">Overlay options</string>
|
||||||
<string name="touchscreen">Touchscreen</string>
|
|
||||||
|
|
||||||
<string name="load_settings">Loading settings…</string>
|
<string name="load_settings">Loading settings…</string>
|
||||||
|
|
||||||
@ -509,12 +506,6 @@
|
|||||||
<string name="oboe">oboe</string>
|
<string name="oboe">oboe</string>
|
||||||
<string name="cubeb">cubeb</string>
|
<string name="cubeb">cubeb</string>
|
||||||
|
|
||||||
<!-- Anisotropic filtering options -->
|
|
||||||
<string name="multiplier_two">2x</string>
|
|
||||||
<string name="multiplier_four">4x</string>
|
|
||||||
<string name="multiplier_eight">8x</string>
|
|
||||||
<string name="multiplier_sixteen">16x</string>
|
|
||||||
|
|
||||||
<!-- Black backgrounds theme -->
|
<!-- Black backgrounds theme -->
|
||||||
<string name="use_black_backgrounds">Black backgrounds</string>
|
<string name="use_black_backgrounds">Black backgrounds</string>
|
||||||
<string name="use_black_backgrounds_description">When using the dark theme, apply black backgrounds.</string>
|
<string name="use_black_backgrounds_description">When using the dark theme, apply black backgrounds.</string>
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("com.android.application") version "8.1.2" apply false
|
id("com.android.application") version "8.1.2" apply false
|
||||||
id("com.android.library") version "8.1.2" apply false
|
id("com.android.library") version "8.1.2" apply false
|
||||||
id("org.jetbrains.kotlin.android") version "1.9.20" apply false
|
id("org.jetbrains.kotlin.android") version "1.8.21" apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register("clean").configure {
|
tasks.register("clean").configure {
|
||||||
|
@ -18,7 +18,9 @@ constexpr auto INCREMENT_TIME{5ms};
|
|||||||
DeviceSession::DeviceSession(Core::System& system_)
|
DeviceSession::DeviceSession(Core::System& system_)
|
||||||
: system{system_}, thread_event{Core::Timing::CreateEvent(
|
: system{system_}, thread_event{Core::Timing::CreateEvent(
|
||||||
"AudioOutSampleTick",
|
"AudioOutSampleTick",
|
||||||
[this](s64 time, std::chrono::nanoseconds) { return ThreadFunc(); })} {}
|
[this](std::uintptr_t, s64 time, std::chrono::nanoseconds) {
|
||||||
|
return ThreadFunc();
|
||||||
|
})} {}
|
||||||
|
|
||||||
DeviceSession::~DeviceSession() {
|
DeviceSession::~DeviceSession() {
|
||||||
Finalize();
|
Finalize();
|
||||||
|
@ -29,7 +29,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
~OboeSinkStream() override {
|
~OboeSinkStream() override {
|
||||||
LOG_INFO(Audio_Sink, "Destroyed Oboe stream");
|
LOG_DEBUG(Audio_Sink, "Destructing Oboe stream {}", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Finalize() override {
|
void Finalize() override {
|
||||||
@ -66,7 +66,11 @@ public:
|
|||||||
std::shared_ptr<oboe::AudioStream> temp_stream;
|
std::shared_ptr<oboe::AudioStream> temp_stream;
|
||||||
oboe::AudioStreamBuilder builder;
|
oboe::AudioStreamBuilder builder;
|
||||||
|
|
||||||
const auto result = ConfigureBuilder(builder, direction)->openStream(temp_stream);
|
const auto result = builder.setDirection(direction)
|
||||||
|
->setSampleRate(TargetSampleRate)
|
||||||
|
->setFormat(oboe::AudioFormat::I16)
|
||||||
|
->setFormatConversionAllowed(true)
|
||||||
|
->openStream(temp_stream);
|
||||||
ASSERT(result == oboe::Result::OK);
|
ASSERT(result == oboe::Result::OK);
|
||||||
|
|
||||||
return temp_stream->getChannelCount() >= 6 ? 6 : 2;
|
return temp_stream->getChannelCount() >= 6 ? 6 : 2;
|
||||||
@ -101,20 +105,6 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static oboe::AudioStreamBuilder* ConfigureBuilder(oboe::AudioStreamBuilder& builder,
|
|
||||||
oboe::Direction direction) {
|
|
||||||
// TODO: investigate callback delay issues when using AAudio
|
|
||||||
return builder.setPerformanceMode(oboe::PerformanceMode::LowLatency)
|
|
||||||
->setAudioApi(oboe::AudioApi::OpenSLES)
|
|
||||||
->setDirection(direction)
|
|
||||||
->setSampleRate(TargetSampleRate)
|
|
||||||
->setSampleRateConversionQuality(oboe::SampleRateConversionQuality::High)
|
|
||||||
->setFormat(oboe::AudioFormat::I16)
|
|
||||||
->setFormatConversionAllowed(true)
|
|
||||||
->setUsage(oboe::Usage::Game)
|
|
||||||
->setBufferCapacityInFrames(TargetSampleCount * 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OpenStream() {
|
bool OpenStream() {
|
||||||
const auto direction = [&]() {
|
const auto direction = [&]() {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@ -145,10 +135,12 @@ private:
|
|||||||
}();
|
}();
|
||||||
|
|
||||||
oboe::AudioStreamBuilder builder;
|
oboe::AudioStreamBuilder builder;
|
||||||
const auto result = ConfigureBuilder(builder, direction)
|
const auto result = builder.setDirection(direction)
|
||||||
|
->setSampleRate(TargetSampleRate)
|
||||||
->setChannelCount(expected_channels)
|
->setChannelCount(expected_channels)
|
||||||
->setChannelMask(expected_mask)
|
->setChannelMask(expected_mask)
|
||||||
->setChannelConversionAllowed(true)
|
->setFormat(oboe::AudioFormat::I16)
|
||||||
|
->setFormatConversionAllowed(true)
|
||||||
->setDataCallback(this)
|
->setDataCallback(this)
|
||||||
->setErrorCallback(this)
|
->setErrorCallback(this)
|
||||||
->openStream(m_stream);
|
->openStream(m_stream);
|
||||||
@ -159,16 +151,8 @@ private:
|
|||||||
bool SetStreamProperties() {
|
bool SetStreamProperties() {
|
||||||
ASSERT(m_stream);
|
ASSERT(m_stream);
|
||||||
|
|
||||||
m_stream->setBufferSizeInFrames(TargetSampleCount * 2);
|
|
||||||
device_channels = m_stream->getChannelCount();
|
device_channels = m_stream->getChannelCount();
|
||||||
|
LOG_INFO(Audio_Sink, "Opened Oboe stream with {} channels", device_channels);
|
||||||
const auto sample_rate = m_stream->getSampleRate();
|
|
||||||
const auto buffer_capacity = m_stream->getBufferCapacityInFrames();
|
|
||||||
const auto stream_backend =
|
|
||||||
m_stream->getAudioApi() == oboe::AudioApi::AAudio ? "AAudio" : "OpenSLES";
|
|
||||||
|
|
||||||
LOG_INFO(Audio_Sink, "Opened Oboe {} stream with {} channels sample rate {} capacity {}",
|
|
||||||
stream_backend, device_channels, sample_rate, buffer_capacity);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -64,8 +64,6 @@ add_library(common STATIC
|
|||||||
fs/path_util.cpp
|
fs/path_util.cpp
|
||||||
fs/path_util.h
|
fs/path_util.h
|
||||||
hash.h
|
hash.h
|
||||||
heap_tracker.cpp
|
|
||||||
heap_tracker.h
|
|
||||||
hex_util.cpp
|
hex_util.cpp
|
||||||
hex_util.h
|
hex_util.h
|
||||||
host_memory.cpp
|
host_memory.cpp
|
||||||
|
@ -3,19 +3,16 @@
|
|||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/logging/backend.h"
|
|
||||||
|
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
|
|
||||||
void assert_fail_impl() {
|
void assert_fail_impl() {
|
||||||
if (Settings::values.use_debug_asserts) {
|
if (Settings::values.use_debug_asserts) {
|
||||||
Common::Log::Stop();
|
|
||||||
Crash();
|
Crash();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[[noreturn]] void unreachable_impl() {
|
[[noreturn]] void unreachable_impl() {
|
||||||
Common::Log::Stop();
|
|
||||||
Crash();
|
Crash();
|
||||||
throw std::runtime_error("Unreachable code");
|
throw std::runtime_error("Unreachable code");
|
||||||
}
|
}
|
||||||
|
@ -1,281 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include <fstream>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "common/heap_tracker.h"
|
|
||||||
#include "common/logging/log.h"
|
|
||||||
|
|
||||||
namespace Common {
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
s64 GetMaxPermissibleResidentMapCount() {
|
|
||||||
// Default value.
|
|
||||||
s64 value = 65530;
|
|
||||||
|
|
||||||
// Try to read how many mappings we can make.
|
|
||||||
std::ifstream s("/proc/sys/vm/max_map_count");
|
|
||||||
s >> value;
|
|
||||||
|
|
||||||
// Print, for debug.
|
|
||||||
LOG_INFO(HW_Memory, "Current maximum map count: {}", value);
|
|
||||||
|
|
||||||
// Allow 20000 maps for other code and to account for split inaccuracy.
|
|
||||||
return std::max<s64>(value - 20000, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
HeapTracker::HeapTracker(Common::HostMemory& buffer)
|
|
||||||
: m_buffer(buffer), m_max_resident_map_count(GetMaxPermissibleResidentMapCount()) {}
|
|
||||||
HeapTracker::~HeapTracker() = default;
|
|
||||||
|
|
||||||
void HeapTracker::Map(size_t virtual_offset, size_t host_offset, size_t length,
|
|
||||||
MemoryPermission perm, bool is_separate_heap) {
|
|
||||||
// When mapping other memory, map pages immediately.
|
|
||||||
if (!is_separate_heap) {
|
|
||||||
m_buffer.Map(virtual_offset, host_offset, length, perm, false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
// We are mapping part of a separate heap.
|
|
||||||
std::scoped_lock lk{m_lock};
|
|
||||||
|
|
||||||
auto* const map = new SeparateHeapMap{
|
|
||||||
.vaddr = virtual_offset,
|
|
||||||
.paddr = host_offset,
|
|
||||||
.size = length,
|
|
||||||
.tick = m_tick++,
|
|
||||||
.perm = perm,
|
|
||||||
.is_resident = false,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Insert into mappings.
|
|
||||||
m_map_count++;
|
|
||||||
m_mappings.insert(*map);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finally, map.
|
|
||||||
this->DeferredMapSeparateHeap(virtual_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HeapTracker::Unmap(size_t virtual_offset, size_t size, bool is_separate_heap) {
|
|
||||||
// If this is a separate heap...
|
|
||||||
if (is_separate_heap) {
|
|
||||||
std::scoped_lock lk{m_lock};
|
|
||||||
|
|
||||||
const SeparateHeapMap key{
|
|
||||||
.vaddr = virtual_offset,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Split at the boundaries of the region we are removing.
|
|
||||||
this->SplitHeapMapLocked(virtual_offset);
|
|
||||||
this->SplitHeapMapLocked(virtual_offset + size);
|
|
||||||
|
|
||||||
// Erase all mappings in range.
|
|
||||||
auto it = m_mappings.find(key);
|
|
||||||
while (it != m_mappings.end() && it->vaddr < virtual_offset + size) {
|
|
||||||
// Get underlying item.
|
|
||||||
auto* const item = std::addressof(*it);
|
|
||||||
|
|
||||||
// If resident, erase from resident map.
|
|
||||||
if (item->is_resident) {
|
|
||||||
ASSERT(--m_resident_map_count >= 0);
|
|
||||||
m_resident_mappings.erase(m_resident_mappings.iterator_to(*item));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Erase from map.
|
|
||||||
ASSERT(--m_map_count >= 0);
|
|
||||||
it = m_mappings.erase(it);
|
|
||||||
|
|
||||||
// Free the item.
|
|
||||||
delete item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unmap pages.
|
|
||||||
m_buffer.Unmap(virtual_offset, size, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HeapTracker::Protect(size_t virtual_offset, size_t size, MemoryPermission perm) {
|
|
||||||
// Ensure no rebuild occurs while reprotecting.
|
|
||||||
std::shared_lock lk{m_rebuild_lock};
|
|
||||||
|
|
||||||
// Split at the boundaries of the region we are reprotecting.
|
|
||||||
this->SplitHeapMap(virtual_offset, size);
|
|
||||||
|
|
||||||
// Declare tracking variables.
|
|
||||||
const VAddr end = virtual_offset + size;
|
|
||||||
VAddr cur = virtual_offset;
|
|
||||||
|
|
||||||
while (cur < end) {
|
|
||||||
VAddr next = cur;
|
|
||||||
bool should_protect = false;
|
|
||||||
|
|
||||||
{
|
|
||||||
std::scoped_lock lk2{m_lock};
|
|
||||||
|
|
||||||
const SeparateHeapMap key{
|
|
||||||
.vaddr = next,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Try to get the next mapping corresponding to this address.
|
|
||||||
const auto it = m_mappings.nfind(key);
|
|
||||||
|
|
||||||
if (it == m_mappings.end()) {
|
|
||||||
// There are no separate heap mappings remaining.
|
|
||||||
next = end;
|
|
||||||
should_protect = true;
|
|
||||||
} else if (it->vaddr == cur) {
|
|
||||||
// We are in range.
|
|
||||||
// Update permission bits.
|
|
||||||
it->perm = perm;
|
|
||||||
|
|
||||||
// Determine next address and whether we should protect.
|
|
||||||
next = cur + it->size;
|
|
||||||
should_protect = it->is_resident;
|
|
||||||
} else /* if (it->vaddr > cur) */ {
|
|
||||||
// We weren't in range, but there is a block coming up that will be.
|
|
||||||
next = it->vaddr;
|
|
||||||
should_protect = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clamp to end.
|
|
||||||
next = std::min(next, end);
|
|
||||||
|
|
||||||
// Reprotect, if we need to.
|
|
||||||
if (should_protect) {
|
|
||||||
m_buffer.Protect(cur, next - cur, perm);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Advance.
|
|
||||||
cur = next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HeapTracker::DeferredMapSeparateHeap(u8* fault_address) {
|
|
||||||
if (m_buffer.IsInVirtualRange(fault_address)) {
|
|
||||||
return this->DeferredMapSeparateHeap(fault_address - m_buffer.VirtualBasePointer());
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HeapTracker::DeferredMapSeparateHeap(size_t virtual_offset) {
|
|
||||||
bool rebuild_required = false;
|
|
||||||
|
|
||||||
{
|
|
||||||
std::scoped_lock lk{m_lock};
|
|
||||||
|
|
||||||
// Check to ensure this was a non-resident separate heap mapping.
|
|
||||||
const auto it = this->GetNearestHeapMapLocked(virtual_offset);
|
|
||||||
if (it == m_mappings.end() || it->is_resident) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update tick before possible rebuild.
|
|
||||||
it->tick = m_tick++;
|
|
||||||
|
|
||||||
// Check if we need to rebuild.
|
|
||||||
if (m_resident_map_count > m_max_resident_map_count) {
|
|
||||||
rebuild_required = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map the area.
|
|
||||||
m_buffer.Map(it->vaddr, it->paddr, it->size, it->perm, false);
|
|
||||||
|
|
||||||
// This map is now resident.
|
|
||||||
it->is_resident = true;
|
|
||||||
m_resident_map_count++;
|
|
||||||
m_resident_mappings.insert(*it);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rebuild_required) {
|
|
||||||
// A rebuild was required, so perform it now.
|
|
||||||
this->RebuildSeparateHeapAddressSpace();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HeapTracker::RebuildSeparateHeapAddressSpace() {
|
|
||||||
std::scoped_lock lk{m_rebuild_lock, m_lock};
|
|
||||||
|
|
||||||
ASSERT(!m_resident_mappings.empty());
|
|
||||||
|
|
||||||
// Dump half of the mappings.
|
|
||||||
//
|
|
||||||
// Despite being worse in theory, this has proven to be better in practice than more
|
|
||||||
// regularly dumping a smaller amount, because it significantly reduces average case
|
|
||||||
// lock contention.
|
|
||||||
const size_t desired_count = std::min(m_resident_map_count, m_max_resident_map_count) / 2;
|
|
||||||
const size_t evict_count = m_resident_map_count - desired_count;
|
|
||||||
auto it = m_resident_mappings.begin();
|
|
||||||
|
|
||||||
for (size_t i = 0; i < evict_count && it != m_resident_mappings.end(); i++) {
|
|
||||||
// Unmark and unmap.
|
|
||||||
it->is_resident = false;
|
|
||||||
m_buffer.Unmap(it->vaddr, it->size, false);
|
|
||||||
|
|
||||||
// Advance.
|
|
||||||
ASSERT(--m_resident_map_count >= 0);
|
|
||||||
it = m_resident_mappings.erase(it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HeapTracker::SplitHeapMap(VAddr offset, size_t size) {
|
|
||||||
std::scoped_lock lk{m_lock};
|
|
||||||
|
|
||||||
this->SplitHeapMapLocked(offset);
|
|
||||||
this->SplitHeapMapLocked(offset + size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HeapTracker::SplitHeapMapLocked(VAddr offset) {
|
|
||||||
const auto it = this->GetNearestHeapMapLocked(offset);
|
|
||||||
if (it == m_mappings.end() || it->vaddr == offset) {
|
|
||||||
// Not contained or no split required.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cache the original values.
|
|
||||||
auto* const left = std::addressof(*it);
|
|
||||||
const size_t orig_size = left->size;
|
|
||||||
|
|
||||||
// Adjust the left map.
|
|
||||||
const size_t left_size = offset - left->vaddr;
|
|
||||||
left->size = left_size;
|
|
||||||
|
|
||||||
// Create the new right map.
|
|
||||||
auto* const right = new SeparateHeapMap{
|
|
||||||
.vaddr = left->vaddr + left_size,
|
|
||||||
.paddr = left->paddr + left_size,
|
|
||||||
.size = orig_size - left_size,
|
|
||||||
.tick = left->tick,
|
|
||||||
.perm = left->perm,
|
|
||||||
.is_resident = left->is_resident,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Insert the new right map.
|
|
||||||
m_map_count++;
|
|
||||||
m_mappings.insert(*right);
|
|
||||||
|
|
||||||
// If resident, also insert into resident map.
|
|
||||||
if (right->is_resident) {
|
|
||||||
m_resident_map_count++;
|
|
||||||
m_resident_mappings.insert(*right);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HeapTracker::AddrTree::iterator HeapTracker::GetNearestHeapMapLocked(VAddr offset) {
|
|
||||||
const SeparateHeapMap key{
|
|
||||||
.vaddr = offset,
|
|
||||||
};
|
|
||||||
|
|
||||||
return m_mappings.find(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Common
|
|
@ -1,98 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <atomic>
|
|
||||||
#include <mutex>
|
|
||||||
#include <set>
|
|
||||||
#include <shared_mutex>
|
|
||||||
|
|
||||||
#include "common/host_memory.h"
|
|
||||||
#include "common/intrusive_red_black_tree.h"
|
|
||||||
|
|
||||||
namespace Common {
|
|
||||||
|
|
||||||
struct SeparateHeapMap {
|
|
||||||
Common::IntrusiveRedBlackTreeNode addr_node{};
|
|
||||||
Common::IntrusiveRedBlackTreeNode tick_node{};
|
|
||||||
VAddr vaddr{};
|
|
||||||
PAddr paddr{};
|
|
||||||
size_t size{};
|
|
||||||
size_t tick{};
|
|
||||||
MemoryPermission perm{};
|
|
||||||
bool is_resident{};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SeparateHeapMapAddrComparator {
|
|
||||||
static constexpr int Compare(const SeparateHeapMap& lhs, const SeparateHeapMap& rhs) {
|
|
||||||
if (lhs.vaddr < rhs.vaddr) {
|
|
||||||
return -1;
|
|
||||||
} else if (lhs.vaddr <= (rhs.vaddr + rhs.size - 1)) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SeparateHeapMapTickComparator {
|
|
||||||
static constexpr int Compare(const SeparateHeapMap& lhs, const SeparateHeapMap& rhs) {
|
|
||||||
if (lhs.tick < rhs.tick) {
|
|
||||||
return -1;
|
|
||||||
} else if (lhs.tick > rhs.tick) {
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
return SeparateHeapMapAddrComparator::Compare(lhs, rhs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class HeapTracker {
|
|
||||||
public:
|
|
||||||
explicit HeapTracker(Common::HostMemory& buffer);
|
|
||||||
~HeapTracker();
|
|
||||||
|
|
||||||
void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perm,
|
|
||||||
bool is_separate_heap);
|
|
||||||
void Unmap(size_t virtual_offset, size_t size, bool is_separate_heap);
|
|
||||||
void Protect(size_t virtual_offset, size_t length, MemoryPermission perm);
|
|
||||||
u8* VirtualBasePointer() {
|
|
||||||
return m_buffer.VirtualBasePointer();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DeferredMapSeparateHeap(u8* fault_address);
|
|
||||||
bool DeferredMapSeparateHeap(size_t virtual_offset);
|
|
||||||
|
|
||||||
private:
|
|
||||||
using AddrTreeTraits =
|
|
||||||
Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&SeparateHeapMap::addr_node>;
|
|
||||||
using AddrTree = AddrTreeTraits::TreeType<SeparateHeapMapAddrComparator>;
|
|
||||||
|
|
||||||
using TickTreeTraits =
|
|
||||||
Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&SeparateHeapMap::tick_node>;
|
|
||||||
using TickTree = TickTreeTraits::TreeType<SeparateHeapMapTickComparator>;
|
|
||||||
|
|
||||||
AddrTree m_mappings{};
|
|
||||||
TickTree m_resident_mappings{};
|
|
||||||
|
|
||||||
private:
|
|
||||||
void SplitHeapMap(VAddr offset, size_t size);
|
|
||||||
void SplitHeapMapLocked(VAddr offset);
|
|
||||||
|
|
||||||
AddrTree::iterator GetNearestHeapMapLocked(VAddr offset);
|
|
||||||
|
|
||||||
void RebuildSeparateHeapAddressSpace();
|
|
||||||
|
|
||||||
private:
|
|
||||||
Common::HostMemory& m_buffer;
|
|
||||||
const s64 m_max_resident_map_count;
|
|
||||||
|
|
||||||
std::shared_mutex m_rebuild_lock{};
|
|
||||||
std::mutex m_lock{};
|
|
||||||
s64 m_map_count{};
|
|
||||||
s64 m_resident_map_count{};
|
|
||||||
size_t m_tick{};
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Common
|
|
@ -679,7 +679,7 @@ HostMemory::HostMemory(HostMemory&&) noexcept = default;
|
|||||||
HostMemory& HostMemory::operator=(HostMemory&&) noexcept = default;
|
HostMemory& HostMemory::operator=(HostMemory&&) noexcept = default;
|
||||||
|
|
||||||
void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length,
|
void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length,
|
||||||
MemoryPermission perms, bool separate_heap) {
|
MemoryPermission perms) {
|
||||||
ASSERT(virtual_offset % PageAlignment == 0);
|
ASSERT(virtual_offset % PageAlignment == 0);
|
||||||
ASSERT(host_offset % PageAlignment == 0);
|
ASSERT(host_offset % PageAlignment == 0);
|
||||||
ASSERT(length % PageAlignment == 0);
|
ASSERT(length % PageAlignment == 0);
|
||||||
@ -691,7 +691,7 @@ void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length,
|
|||||||
impl->Map(virtual_offset + virtual_base_offset, host_offset, length, perms);
|
impl->Map(virtual_offset + virtual_base_offset, host_offset, length, perms);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HostMemory::Unmap(size_t virtual_offset, size_t length, bool separate_heap) {
|
void HostMemory::Unmap(size_t virtual_offset, size_t length) {
|
||||||
ASSERT(virtual_offset % PageAlignment == 0);
|
ASSERT(virtual_offset % PageAlignment == 0);
|
||||||
ASSERT(length % PageAlignment == 0);
|
ASSERT(length % PageAlignment == 0);
|
||||||
ASSERT(virtual_offset + length <= virtual_size);
|
ASSERT(virtual_offset + length <= virtual_size);
|
||||||
@ -701,16 +701,14 @@ void HostMemory::Unmap(size_t virtual_offset, size_t length, bool separate_heap)
|
|||||||
impl->Unmap(virtual_offset + virtual_base_offset, length);
|
impl->Unmap(virtual_offset + virtual_base_offset, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HostMemory::Protect(size_t virtual_offset, size_t length, MemoryPermission perm) {
|
void HostMemory::Protect(size_t virtual_offset, size_t length, bool read, bool write,
|
||||||
|
bool execute) {
|
||||||
ASSERT(virtual_offset % PageAlignment == 0);
|
ASSERT(virtual_offset % PageAlignment == 0);
|
||||||
ASSERT(length % PageAlignment == 0);
|
ASSERT(length % PageAlignment == 0);
|
||||||
ASSERT(virtual_offset + length <= virtual_size);
|
ASSERT(virtual_offset + length <= virtual_size);
|
||||||
if (length == 0 || !virtual_base || !impl) {
|
if (length == 0 || !virtual_base || !impl) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const bool read = True(perm & MemoryPermission::Read);
|
|
||||||
const bool write = True(perm & MemoryPermission::Write);
|
|
||||||
const bool execute = True(perm & MemoryPermission::Execute);
|
|
||||||
impl->Protect(virtual_offset + virtual_base_offset, length, read, write, execute);
|
impl->Protect(virtual_offset + virtual_base_offset, length, read, write, execute);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,12 +40,11 @@ public:
|
|||||||
HostMemory(HostMemory&& other) noexcept;
|
HostMemory(HostMemory&& other) noexcept;
|
||||||
HostMemory& operator=(HostMemory&& other) noexcept;
|
HostMemory& operator=(HostMemory&& other) noexcept;
|
||||||
|
|
||||||
void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perms,
|
void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perms);
|
||||||
bool separate_heap);
|
|
||||||
|
|
||||||
void Unmap(size_t virtual_offset, size_t length, bool separate_heap);
|
void Unmap(size_t virtual_offset, size_t length);
|
||||||
|
|
||||||
void Protect(size_t virtual_offset, size_t length, MemoryPermission perms);
|
void Protect(size_t virtual_offset, size_t length, bool read, bool write, bool execute = false);
|
||||||
|
|
||||||
void EnableDirectMappedAddress();
|
void EnableDirectMappedAddress();
|
||||||
|
|
||||||
@ -65,10 +64,6 @@ public:
|
|||||||
return virtual_base;
|
return virtual_base;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsInVirtualRange(void* address) const noexcept {
|
|
||||||
return address >= virtual_base && address < virtual_base + virtual_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
size_t backing_size{};
|
size_t backing_size{};
|
||||||
size_t virtual_size{};
|
size_t virtual_size{};
|
||||||
|
@ -208,10 +208,6 @@ public:
|
|||||||
instance->StartBackendThread();
|
instance->StartBackendThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Stop() {
|
|
||||||
instance->StopBackendThread();
|
|
||||||
}
|
|
||||||
|
|
||||||
Impl(const Impl&) = delete;
|
Impl(const Impl&) = delete;
|
||||||
Impl& operator=(const Impl&) = delete;
|
Impl& operator=(const Impl&) = delete;
|
||||||
|
|
||||||
@ -263,15 +259,6 @@ private:
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void StopBackendThread() {
|
|
||||||
backend_thread.request_stop();
|
|
||||||
if (backend_thread.joinable()) {
|
|
||||||
backend_thread.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
ForEachBackend([](Backend& backend) { backend.Flush(); });
|
|
||||||
}
|
|
||||||
|
|
||||||
Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
|
Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
|
||||||
const char* function, std::string&& message) const {
|
const char* function, std::string&& message) const {
|
||||||
using std::chrono::duration_cast;
|
using std::chrono::duration_cast;
|
||||||
@ -326,10 +313,6 @@ void Start() {
|
|||||||
Impl::Start();
|
Impl::Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stop() {
|
|
||||||
Impl::Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DisableLoggingInTests() {
|
void DisableLoggingInTests() {
|
||||||
initialization_in_progress_suppress_logging = true;
|
initialization_in_progress_suppress_logging = true;
|
||||||
}
|
}
|
||||||
|
@ -14,9 +14,6 @@ void Initialize();
|
|||||||
|
|
||||||
void Start();
|
void Start();
|
||||||
|
|
||||||
/// Explicitly stops the logger thread and flushes the buffers
|
|
||||||
void Stop();
|
|
||||||
|
|
||||||
void DisableLoggingInTests();
|
void DisableLoggingInTests();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -103,7 +103,7 @@ private:
|
|||||||
// Having them on the same cache-line would result in false-sharing between them.
|
// Having them on the same cache-line would result in false-sharing between them.
|
||||||
// TODO: Remove this ifdef whenever clang and GCC support
|
// TODO: Remove this ifdef whenever clang and GCC support
|
||||||
// std::hardware_destructive_interference_size.
|
// std::hardware_destructive_interference_size.
|
||||||
#ifdef __cpp_lib_hardware_interference_size
|
#if defined(_MSC_VER) && _MSC_VER >= 1911
|
||||||
alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_read_index{0};
|
alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_read_index{0};
|
||||||
alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_write_index{0};
|
alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_write_index{0};
|
||||||
#else
|
#else
|
||||||
|
@ -199,8 +199,6 @@ const char* TranslateCategory(Category category) {
|
|||||||
case Category::CpuDebug:
|
case Category::CpuDebug:
|
||||||
case Category::CpuUnsafe:
|
case Category::CpuUnsafe:
|
||||||
return "Cpu";
|
return "Cpu";
|
||||||
case Category::Overlay:
|
|
||||||
return "Overlay";
|
|
||||||
case Category::Renderer:
|
case Category::Renderer:
|
||||||
case Category::RendererAdvanced:
|
case Category::RendererAdvanced:
|
||||||
case Category::RendererDebug:
|
case Category::RendererDebug:
|
||||||
|
@ -18,7 +18,6 @@ enum class Category : u32 {
|
|||||||
Cpu,
|
Cpu,
|
||||||
CpuDebug,
|
CpuDebug,
|
||||||
CpuUnsafe,
|
CpuUnsafe,
|
||||||
Overlay,
|
|
||||||
Renderer,
|
Renderer,
|
||||||
RendererAdvanced,
|
RendererAdvanced,
|
||||||
RendererDebug,
|
RendererDebug,
|
||||||
|
@ -978,7 +978,6 @@ endif()
|
|||||||
|
|
||||||
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
|
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
|
||||||
target_sources(core PRIVATE
|
target_sources(core PRIVATE
|
||||||
arm/dynarmic/arm_dynarmic.cpp
|
|
||||||
arm/dynarmic/arm_dynarmic.h
|
arm/dynarmic/arm_dynarmic.h
|
||||||
arm/dynarmic/arm_dynarmic_64.cpp
|
arm/dynarmic/arm_dynarmic_64.cpp
|
||||||
arm/dynarmic/arm_dynarmic_64.h
|
arm/dynarmic/arm_dynarmic_64.h
|
||||||
@ -988,8 +987,6 @@ if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
|
|||||||
arm/dynarmic/dynarmic_cp15.h
|
arm/dynarmic/dynarmic_cp15.h
|
||||||
arm/dynarmic/dynarmic_exclusive_monitor.cpp
|
arm/dynarmic/dynarmic_exclusive_monitor.cpp
|
||||||
arm/dynarmic/dynarmic_exclusive_monitor.h
|
arm/dynarmic/dynarmic_exclusive_monitor.h
|
||||||
hle/service/jit/jit_code_memory.cpp
|
|
||||||
hle/service/jit/jit_code_memory.h
|
|
||||||
hle/service/jit/jit_context.cpp
|
hle/service/jit/jit_context.cpp
|
||||||
hle/service/jit/jit_context.h
|
hle/service/jit/jit_context.h
|
||||||
hle/service/jit/jit.cpp
|
hle/service/jit/jit.cpp
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
void ArmInterface::LogBacktrace(Kernel::KProcess* process) const {
|
void ArmInterface::LogBacktrace(const Kernel::KProcess* process) const {
|
||||||
Kernel::Svc::ThreadContext ctx;
|
Kernel::Svc::ThreadContext ctx;
|
||||||
this->GetContext(ctx);
|
this->GetContext(ctx);
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ public:
|
|||||||
virtual void SignalInterrupt(Kernel::KThread* thread) = 0;
|
virtual void SignalInterrupt(Kernel::KThread* thread) = 0;
|
||||||
|
|
||||||
// Stack trace generation.
|
// Stack trace generation.
|
||||||
void LogBacktrace(Kernel::KProcess* process) const;
|
void LogBacktrace(const Kernel::KProcess* process) const;
|
||||||
|
|
||||||
// Debug functionality.
|
// Debug functionality.
|
||||||
virtual const Kernel::DebugWatchpoint* HaltedWatchpoint() const = 0;
|
virtual const Kernel::DebugWatchpoint* HaltedWatchpoint() const = 0;
|
||||||
|
@ -79,7 +79,7 @@ constexpr std::array<u64, 2> SegmentBases{
|
|||||||
0x7100000000ULL,
|
0x7100000000ULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
void SymbolicateBacktrace(Kernel::KProcess* process, std::vector<BacktraceEntry>& out) {
|
void SymbolicateBacktrace(const Kernel::KProcess* process, std::vector<BacktraceEntry>& out) {
|
||||||
auto modules = FindModules(process);
|
auto modules = FindModules(process);
|
||||||
|
|
||||||
const bool is_64 = process->Is64Bit();
|
const bool is_64 = process->Is64Bit();
|
||||||
@ -118,7 +118,7 @@ void SymbolicateBacktrace(Kernel::KProcess* process, std::vector<BacktraceEntry>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<BacktraceEntry> GetAArch64Backtrace(Kernel::KProcess* process,
|
std::vector<BacktraceEntry> GetAArch64Backtrace(const Kernel::KProcess* process,
|
||||||
const Kernel::Svc::ThreadContext& ctx) {
|
const Kernel::Svc::ThreadContext& ctx) {
|
||||||
std::vector<BacktraceEntry> out;
|
std::vector<BacktraceEntry> out;
|
||||||
auto& memory = process->GetMemory();
|
auto& memory = process->GetMemory();
|
||||||
@ -144,7 +144,7 @@ std::vector<BacktraceEntry> GetAArch64Backtrace(Kernel::KProcess* process,
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<BacktraceEntry> GetAArch32Backtrace(Kernel::KProcess* process,
|
std::vector<BacktraceEntry> GetAArch32Backtrace(const Kernel::KProcess* process,
|
||||||
const Kernel::Svc::ThreadContext& ctx) {
|
const Kernel::Svc::ThreadContext& ctx) {
|
||||||
std::vector<BacktraceEntry> out;
|
std::vector<BacktraceEntry> out;
|
||||||
auto& memory = process->GetMemory();
|
auto& memory = process->GetMemory();
|
||||||
@ -173,7 +173,7 @@ std::vector<BacktraceEntry> GetAArch32Backtrace(Kernel::KProcess* process,
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
std::optional<std::string> GetThreadName(const Kernel::KThread* thread) {
|
std::optional<std::string> GetThreadName(const Kernel::KThread* thread) {
|
||||||
auto* process = thread->GetOwnerProcess();
|
const auto* process = thread->GetOwnerProcess();
|
||||||
if (process->Is64Bit()) {
|
if (process->Is64Bit()) {
|
||||||
return GetNameFromThreadType64(process->GetMemory(), *thread);
|
return GetNameFromThreadType64(process->GetMemory(), *thread);
|
||||||
} else {
|
} else {
|
||||||
@ -248,7 +248,7 @@ Kernel::KProcessAddress GetModuleEnd(const Kernel::KProcess* process,
|
|||||||
return cur_addr - 1;
|
return cur_addr - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader::AppLoader::Modules FindModules(Kernel::KProcess* process) {
|
Loader::AppLoader::Modules FindModules(const Kernel::KProcess* process) {
|
||||||
Loader::AppLoader::Modules modules;
|
Loader::AppLoader::Modules modules;
|
||||||
|
|
||||||
auto& page_table = process->GetPageTable();
|
auto& page_table = process->GetPageTable();
|
||||||
@ -312,7 +312,7 @@ Loader::AppLoader::Modules FindModules(Kernel::KProcess* process) {
|
|||||||
return modules;
|
return modules;
|
||||||
}
|
}
|
||||||
|
|
||||||
Kernel::KProcessAddress FindMainModuleEntrypoint(Kernel::KProcess* process) {
|
Kernel::KProcessAddress FindMainModuleEntrypoint(const Kernel::KProcess* process) {
|
||||||
// Do we have any loaded executable sections?
|
// Do we have any loaded executable sections?
|
||||||
auto modules = FindModules(process);
|
auto modules = FindModules(process);
|
||||||
|
|
||||||
@ -337,7 +337,7 @@ void InvalidateInstructionCacheRange(const Kernel::KProcess* process, u64 addres
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<BacktraceEntry> GetBacktraceFromContext(Kernel::KProcess* process,
|
std::vector<BacktraceEntry> GetBacktraceFromContext(const Kernel::KProcess* process,
|
||||||
const Kernel::Svc::ThreadContext& ctx) {
|
const Kernel::Svc::ThreadContext& ctx) {
|
||||||
if (process->Is64Bit()) {
|
if (process->Is64Bit()) {
|
||||||
return GetAArch64Backtrace(process, ctx);
|
return GetAArch64Backtrace(process, ctx);
|
||||||
|
@ -14,9 +14,9 @@ std::optional<std::string> GetThreadName(const Kernel::KThread* thread);
|
|||||||
std::string_view GetThreadWaitReason(const Kernel::KThread* thread);
|
std::string_view GetThreadWaitReason(const Kernel::KThread* thread);
|
||||||
std::string GetThreadState(const Kernel::KThread* thread);
|
std::string GetThreadState(const Kernel::KThread* thread);
|
||||||
|
|
||||||
Loader::AppLoader::Modules FindModules(Kernel::KProcess* process);
|
Loader::AppLoader::Modules FindModules(const Kernel::KProcess* process);
|
||||||
Kernel::KProcessAddress GetModuleEnd(const Kernel::KProcess* process, Kernel::KProcessAddress base);
|
Kernel::KProcessAddress GetModuleEnd(const Kernel::KProcess* process, Kernel::KProcessAddress base);
|
||||||
Kernel::KProcessAddress FindMainModuleEntrypoint(Kernel::KProcess* process);
|
Kernel::KProcessAddress FindMainModuleEntrypoint(const Kernel::KProcess* process);
|
||||||
|
|
||||||
void InvalidateInstructionCacheRange(const Kernel::KProcess* process, u64 address, u64 size);
|
void InvalidateInstructionCacheRange(const Kernel::KProcess* process, u64 address, u64 size);
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ struct BacktraceEntry {
|
|||||||
std::string name;
|
std::string name;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<BacktraceEntry> GetBacktraceFromContext(Kernel::KProcess* process,
|
std::vector<BacktraceEntry> GetBacktraceFromContext(const Kernel::KProcess* process,
|
||||||
const Kernel::Svc::ThreadContext& ctx);
|
const Kernel::Svc::ThreadContext& ctx);
|
||||||
std::vector<BacktraceEntry> GetBacktrace(const Kernel::KThread* thread);
|
std::vector<BacktraceEntry> GetBacktrace(const Kernel::KThread* thread);
|
||||||
|
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#ifdef __linux__
|
|
||||||
|
|
||||||
#include "common/signal_chain.h"
|
|
||||||
|
|
||||||
#include "core/arm/dynarmic/arm_dynarmic.h"
|
|
||||||
#include "core/hle/kernel/k_process.h"
|
|
||||||
#include "core/memory.h"
|
|
||||||
|
|
||||||
namespace Core {
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
thread_local Core::Memory::Memory* g_current_memory{};
|
|
||||||
std::once_flag g_registered{};
|
|
||||||
struct sigaction g_old_segv {};
|
|
||||||
|
|
||||||
void HandleSigSegv(int sig, siginfo_t* info, void* ctx) {
|
|
||||||
if (g_current_memory && g_current_memory->InvalidateSeparateHeap(info->si_addr)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return g_old_segv.sa_sigaction(sig, info, ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
ScopedJitExecution::ScopedJitExecution(Kernel::KProcess* process) {
|
|
||||||
g_current_memory = std::addressof(process->GetMemory());
|
|
||||||
}
|
|
||||||
|
|
||||||
ScopedJitExecution::~ScopedJitExecution() {
|
|
||||||
g_current_memory = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScopedJitExecution::RegisterHandler() {
|
|
||||||
std::call_once(g_registered, [] {
|
|
||||||
struct sigaction sa {};
|
|
||||||
sa.sa_sigaction = &HandleSigSegv;
|
|
||||||
sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
|
||||||
Common::SigAction(SIGSEGV, std::addressof(sa), std::addressof(g_old_segv));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Core
|
|
||||||
|
|
||||||
#endif
|
|
@ -26,24 +26,4 @@ constexpr HaltReason TranslateHaltReason(Dynarmic::HaltReason hr) {
|
|||||||
return static_cast<HaltReason>(hr);
|
return static_cast<HaltReason>(hr);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __linux__
|
|
||||||
|
|
||||||
class ScopedJitExecution {
|
|
||||||
public:
|
|
||||||
explicit ScopedJitExecution(Kernel::KProcess* process);
|
|
||||||
~ScopedJitExecution();
|
|
||||||
static void RegisterHandler();
|
|
||||||
};
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
class ScopedJitExecution {
|
|
||||||
public:
|
|
||||||
explicit ScopedJitExecution(Kernel::KProcess* process) {}
|
|
||||||
~ScopedJitExecution() {}
|
|
||||||
static void RegisterHandler() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
@ -15,7 +15,7 @@ using namespace Common::Literals;
|
|||||||
|
|
||||||
class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {
|
class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {
|
||||||
public:
|
public:
|
||||||
explicit DynarmicCallbacks32(ArmDynarmic32& parent, Kernel::KProcess* process)
|
explicit DynarmicCallbacks32(ArmDynarmic32& parent, const Kernel::KProcess* process)
|
||||||
: m_parent{parent}, m_memory(process->GetMemory()),
|
: m_parent{parent}, m_memory(process->GetMemory()),
|
||||||
m_process(process), m_debugger_enabled{parent.m_system.DebuggerEnabled()},
|
m_process(process), m_debugger_enabled{parent.m_system.DebuggerEnabled()},
|
||||||
m_check_memory_access{m_debugger_enabled ||
|
m_check_memory_access{m_debugger_enabled ||
|
||||||
@ -169,7 +169,7 @@ public:
|
|||||||
|
|
||||||
ArmDynarmic32& m_parent;
|
ArmDynarmic32& m_parent;
|
||||||
Core::Memory::Memory& m_memory;
|
Core::Memory::Memory& m_memory;
|
||||||
Kernel::KProcess* m_process{};
|
const Kernel::KProcess* m_process{};
|
||||||
const bool m_debugger_enabled{};
|
const bool m_debugger_enabled{};
|
||||||
const bool m_check_memory_access{};
|
const bool m_check_memory_access{};
|
||||||
static constexpr u64 MinimumRunCycles = 10000U;
|
static constexpr u64 MinimumRunCycles = 10000U;
|
||||||
@ -331,15 +331,11 @@ bool ArmDynarmic32::IsInThumbMode() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
HaltReason ArmDynarmic32::RunThread(Kernel::KThread* thread) {
|
HaltReason ArmDynarmic32::RunThread(Kernel::KThread* thread) {
|
||||||
ScopedJitExecution sj(thread->GetOwnerProcess());
|
|
||||||
|
|
||||||
m_jit->ClearExclusiveState();
|
m_jit->ClearExclusiveState();
|
||||||
return TranslateHaltReason(m_jit->Run());
|
return TranslateHaltReason(m_jit->Run());
|
||||||
}
|
}
|
||||||
|
|
||||||
HaltReason ArmDynarmic32::StepThread(Kernel::KThread* thread) {
|
HaltReason ArmDynarmic32::StepThread(Kernel::KThread* thread) {
|
||||||
ScopedJitExecution sj(thread->GetOwnerProcess());
|
|
||||||
|
|
||||||
m_jit->ClearExclusiveState();
|
m_jit->ClearExclusiveState();
|
||||||
return TranslateHaltReason(m_jit->Step());
|
return TranslateHaltReason(m_jit->Step());
|
||||||
}
|
}
|
||||||
@ -374,14 +370,13 @@ void ArmDynarmic32::RewindBreakpointInstruction() {
|
|||||||
this->SetContext(m_breakpoint_context);
|
this->SetContext(m_breakpoint_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
ArmDynarmic32::ArmDynarmic32(System& system, bool uses_wall_clock, Kernel::KProcess* process,
|
ArmDynarmic32::ArmDynarmic32(System& system, bool uses_wall_clock, const Kernel::KProcess* process,
|
||||||
DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index)
|
DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index)
|
||||||
: ArmInterface{uses_wall_clock}, m_system{system}, m_exclusive_monitor{exclusive_monitor},
|
: ArmInterface{uses_wall_clock}, m_system{system}, m_exclusive_monitor{exclusive_monitor},
|
||||||
m_cb(std::make_unique<DynarmicCallbacks32>(*this, process)),
|
m_cb(std::make_unique<DynarmicCallbacks32>(*this, process)),
|
||||||
m_cp15(std::make_shared<DynarmicCP15>(*this)), m_core_index{core_index} {
|
m_cp15(std::make_shared<DynarmicCP15>(*this)), m_core_index{core_index} {
|
||||||
auto& page_table_impl = process->GetPageTable().GetBasePageTable().GetImpl();
|
auto& page_table_impl = process->GetPageTable().GetBasePageTable().GetImpl();
|
||||||
m_jit = MakeJit(&page_table_impl);
|
m_jit = MakeJit(&page_table_impl);
|
||||||
ScopedJitExecution::RegisterHandler();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ArmDynarmic32::~ArmDynarmic32() = default;
|
ArmDynarmic32::~ArmDynarmic32() = default;
|
||||||
|
@ -20,7 +20,7 @@ class System;
|
|||||||
|
|
||||||
class ArmDynarmic32 final : public ArmInterface {
|
class ArmDynarmic32 final : public ArmInterface {
|
||||||
public:
|
public:
|
||||||
ArmDynarmic32(System& system, bool uses_wall_clock, Kernel::KProcess* process,
|
ArmDynarmic32(System& system, bool uses_wall_clock, const Kernel::KProcess* process,
|
||||||
DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index);
|
DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index);
|
||||||
~ArmDynarmic32() override;
|
~ArmDynarmic32() override;
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ using namespace Common::Literals;
|
|||||||
|
|
||||||
class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks {
|
class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks {
|
||||||
public:
|
public:
|
||||||
explicit DynarmicCallbacks64(ArmDynarmic64& parent, Kernel::KProcess* process)
|
explicit DynarmicCallbacks64(ArmDynarmic64& parent, const Kernel::KProcess* process)
|
||||||
: m_parent{parent}, m_memory(process->GetMemory()),
|
: m_parent{parent}, m_memory(process->GetMemory()),
|
||||||
m_process(process), m_debugger_enabled{parent.m_system.DebuggerEnabled()},
|
m_process(process), m_debugger_enabled{parent.m_system.DebuggerEnabled()},
|
||||||
m_check_memory_access{m_debugger_enabled ||
|
m_check_memory_access{m_debugger_enabled ||
|
||||||
@ -216,7 +216,7 @@ public:
|
|||||||
Core::Memory::Memory& m_memory;
|
Core::Memory::Memory& m_memory;
|
||||||
u64 m_tpidrro_el0{};
|
u64 m_tpidrro_el0{};
|
||||||
u64 m_tpidr_el0{};
|
u64 m_tpidr_el0{};
|
||||||
Kernel::KProcess* m_process{};
|
const Kernel::KProcess* m_process{};
|
||||||
const bool m_debugger_enabled{};
|
const bool m_debugger_enabled{};
|
||||||
const bool m_check_memory_access{};
|
const bool m_check_memory_access{};
|
||||||
static constexpr u64 MinimumRunCycles = 10000U;
|
static constexpr u64 MinimumRunCycles = 10000U;
|
||||||
@ -362,15 +362,11 @@ std::shared_ptr<Dynarmic::A64::Jit> ArmDynarmic64::MakeJit(Common::PageTable* pa
|
|||||||
}
|
}
|
||||||
|
|
||||||
HaltReason ArmDynarmic64::RunThread(Kernel::KThread* thread) {
|
HaltReason ArmDynarmic64::RunThread(Kernel::KThread* thread) {
|
||||||
ScopedJitExecution sj(thread->GetOwnerProcess());
|
|
||||||
|
|
||||||
m_jit->ClearExclusiveState();
|
m_jit->ClearExclusiveState();
|
||||||
return TranslateHaltReason(m_jit->Run());
|
return TranslateHaltReason(m_jit->Run());
|
||||||
}
|
}
|
||||||
|
|
||||||
HaltReason ArmDynarmic64::StepThread(Kernel::KThread* thread) {
|
HaltReason ArmDynarmic64::StepThread(Kernel::KThread* thread) {
|
||||||
ScopedJitExecution sj(thread->GetOwnerProcess());
|
|
||||||
|
|
||||||
m_jit->ClearExclusiveState();
|
m_jit->ClearExclusiveState();
|
||||||
return TranslateHaltReason(m_jit->Step());
|
return TranslateHaltReason(m_jit->Step());
|
||||||
}
|
}
|
||||||
@ -403,14 +399,13 @@ void ArmDynarmic64::RewindBreakpointInstruction() {
|
|||||||
this->SetContext(m_breakpoint_context);
|
this->SetContext(m_breakpoint_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
ArmDynarmic64::ArmDynarmic64(System& system, bool uses_wall_clock, Kernel::KProcess* process,
|
ArmDynarmic64::ArmDynarmic64(System& system, bool uses_wall_clock, const Kernel::KProcess* process,
|
||||||
DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index)
|
DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index)
|
||||||
: ArmInterface{uses_wall_clock}, m_system{system}, m_exclusive_monitor{exclusive_monitor},
|
: ArmInterface{uses_wall_clock}, m_system{system}, m_exclusive_monitor{exclusive_monitor},
|
||||||
m_cb(std::make_unique<DynarmicCallbacks64>(*this, process)), m_core_index{core_index} {
|
m_cb(std::make_unique<DynarmicCallbacks64>(*this, process)), m_core_index{core_index} {
|
||||||
auto& page_table = process->GetPageTable().GetBasePageTable();
|
auto& page_table = process->GetPageTable().GetBasePageTable();
|
||||||
auto& page_table_impl = page_table.GetImpl();
|
auto& page_table_impl = page_table.GetImpl();
|
||||||
m_jit = MakeJit(&page_table_impl, page_table.GetAddressSpaceWidth());
|
m_jit = MakeJit(&page_table_impl, page_table.GetAddressSpaceWidth());
|
||||||
ScopedJitExecution::RegisterHandler();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ArmDynarmic64::~ArmDynarmic64() = default;
|
ArmDynarmic64::~ArmDynarmic64() = default;
|
||||||
|
@ -25,7 +25,7 @@ class System;
|
|||||||
|
|
||||||
class ArmDynarmic64 final : public ArmInterface {
|
class ArmDynarmic64 final : public ArmInterface {
|
||||||
public:
|
public:
|
||||||
ArmDynarmic64(System& system, bool uses_wall_clock, Kernel::KProcess* process,
|
ArmDynarmic64(System& system, bool uses_wall_clock, const Kernel::KProcess* process,
|
||||||
DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index);
|
DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index);
|
||||||
~ArmDynarmic64() override;
|
~ArmDynarmic64() override;
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ fpsimd_context* GetFloatingPointState(mcontext_t& host_ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
using namespace Common::Literals;
|
using namespace Common::Literals;
|
||||||
constexpr u32 StackSize = 128_KiB;
|
constexpr u32 StackSize = 32_KiB;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
#include "common/bit_cast.h"
|
#include "common/bit_cast.h"
|
||||||
#include "core/arm/nce/interpreter_visitor.h"
|
#include "core/arm/nce/interpreter_visitor.h"
|
||||||
|
|
||||||
|
#include <dynarmic/frontend/A64/decoder/a64.h>
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
template <u32 BitSize>
|
template <u32 BitSize>
|
||||||
@ -247,7 +249,6 @@ bool InterpreterVisitor::LDR_lit_fpsimd(Imm<2> opc, Imm<19> imm19, Vec Vt) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size in bytes
|
|
||||||
const u64 size = 4 << opc.ZeroExtend();
|
const u64 size = 4 << opc.ZeroExtend();
|
||||||
const u64 offset = imm19.SignExtend<u64>() << 2;
|
const u64 offset = imm19.SignExtend<u64>() << 2;
|
||||||
const u64 address = this->GetPc() + offset;
|
const u64 address = this->GetPc() + offset;
|
||||||
@ -529,7 +530,7 @@ bool InterpreterVisitor::SIMDImmediate(bool wback, bool postindex, size_t scale,
|
|||||||
}
|
}
|
||||||
case MemOp::Load: {
|
case MemOp::Load: {
|
||||||
u128 data{};
|
u128 data{};
|
||||||
m_memory.ReadBlock(address, &data, datasize / 8);
|
m_memory.ReadBlock(address, &data, datasize);
|
||||||
this->SetVec(Vt, data);
|
this->SetVec(Vt, data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -4,15 +4,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#pragma GCC diagnostic push
|
|
||||||
#pragma GCC diagnostic ignored "-Wshadow"
|
|
||||||
|
|
||||||
#include <dynarmic/frontend/A64/a64_types.h>
|
#include <dynarmic/frontend/A64/a64_types.h>
|
||||||
#include <dynarmic/frontend/A64/decoder/a64.h>
|
|
||||||
#include <dynarmic/frontend/imm.h>
|
#include <dynarmic/frontend/imm.h>
|
||||||
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
class VisitorBase {
|
class VisitorBase {
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "core/file_sys/savedata_factory.h"
|
#include "core/file_sys/savedata_factory.h"
|
||||||
#include "core/file_sys/vfs_concat.h"
|
#include "core/file_sys/vfs_concat.h"
|
||||||
#include "core/file_sys/vfs_real.h"
|
#include "core/file_sys/vfs_real.h"
|
||||||
|
#include "core/gpu_dirty_memory_manager.h"
|
||||||
#include "core/hid/hid_core.h"
|
#include "core/hid/hid_core.h"
|
||||||
#include "core/hle/kernel/k_memory_manager.h"
|
#include "core/hle/kernel/k_memory_manager.h"
|
||||||
#include "core/hle/kernel/k_process.h"
|
#include "core/hle/kernel/k_process.h"
|
||||||
@ -129,8 +130,11 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
|
|||||||
|
|
||||||
struct System::Impl {
|
struct System::Impl {
|
||||||
explicit Impl(System& system)
|
explicit Impl(System& system)
|
||||||
: kernel{system}, fs_controller{system}, hid_core{}, room_network{}, cpu_manager{system},
|
: kernel{system}, fs_controller{system}, memory{system}, hid_core{}, room_network{},
|
||||||
reporter{system}, applet_manager{system}, profile_manager{}, time_manager{system} {}
|
cpu_manager{system}, reporter{system}, applet_manager{system}, profile_manager{},
|
||||||
|
time_manager{system}, gpu_dirty_memory_write_manager{} {
|
||||||
|
memory.SetGPUDirtyManagers(gpu_dirty_memory_write_manager);
|
||||||
|
}
|
||||||
|
|
||||||
void Initialize(System& system) {
|
void Initialize(System& system) {
|
||||||
device_memory = std::make_unique<Core::DeviceMemory>();
|
device_memory = std::make_unique<Core::DeviceMemory>();
|
||||||
@ -237,17 +241,17 @@ struct System::Impl {
|
|||||||
debugger = std::make_unique<Debugger>(system, port);
|
debugger = std::make_unique<Debugger>(system, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeKernel(System& system) {
|
SystemResultStatus SetupForApplicationProcess(System& system, Frontend::EmuWindow& emu_window) {
|
||||||
LOG_DEBUG(Core, "initialized OK");
|
LOG_DEBUG(Core, "initialized OK");
|
||||||
|
|
||||||
// Setting changes may require a full system reinitialization (e.g., disabling multicore).
|
// Setting changes may require a full system reinitialization (e.g., disabling multicore).
|
||||||
ReinitializeIfNecessary(system);
|
ReinitializeIfNecessary(system);
|
||||||
|
|
||||||
|
memory.SetGPUDirtyManagers(gpu_dirty_memory_write_manager);
|
||||||
|
|
||||||
kernel.Initialize();
|
kernel.Initialize();
|
||||||
cpu_manager.Initialize();
|
cpu_manager.Initialize();
|
||||||
}
|
|
||||||
|
|
||||||
SystemResultStatus SetupForApplicationProcess(System& system, Frontend::EmuWindow& emu_window) {
|
|
||||||
/// Reset all glue registrations
|
/// Reset all glue registrations
|
||||||
arp_manager.ResetAll();
|
arp_manager.ResetAll();
|
||||||
|
|
||||||
@ -296,9 +300,17 @@ struct System::Impl {
|
|||||||
return SystemResultStatus::ErrorGetLoader;
|
return SystemResultStatus::ErrorGetLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
InitializeKernel(system);
|
SystemResultStatus init_result{SetupForApplicationProcess(system, emu_window)};
|
||||||
|
if (init_result != SystemResultStatus::Success) {
|
||||||
|
LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
|
||||||
|
static_cast<int>(init_result));
|
||||||
|
ShutdownMainProcess();
|
||||||
|
return init_result;
|
||||||
|
}
|
||||||
|
|
||||||
// Create the application process.
|
telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider);
|
||||||
|
|
||||||
|
// Create the process.
|
||||||
auto main_process = Kernel::KProcess::Create(system.Kernel());
|
auto main_process = Kernel::KProcess::Create(system.Kernel());
|
||||||
Kernel::KProcess::Register(system.Kernel(), main_process);
|
Kernel::KProcess::Register(system.Kernel(), main_process);
|
||||||
kernel.AppendNewProcess(main_process);
|
kernel.AppendNewProcess(main_process);
|
||||||
@ -311,18 +323,7 @@ struct System::Impl {
|
|||||||
return static_cast<SystemResultStatus>(
|
return static_cast<SystemResultStatus>(
|
||||||
static_cast<u32>(SystemResultStatus::ErrorLoader) + static_cast<u32>(load_result));
|
static_cast<u32>(SystemResultStatus::ErrorLoader) + static_cast<u32>(load_result));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up the rest of the system.
|
|
||||||
SystemResultStatus init_result{SetupForApplicationProcess(system, emu_window)};
|
|
||||||
if (init_result != SystemResultStatus::Success) {
|
|
||||||
LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
|
|
||||||
static_cast<int>(init_result));
|
|
||||||
ShutdownMainProcess();
|
|
||||||
return init_result;
|
|
||||||
}
|
|
||||||
|
|
||||||
AddGlueRegistrationForProcess(*app_loader, *main_process);
|
AddGlueRegistrationForProcess(*app_loader, *main_process);
|
||||||
telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider);
|
|
||||||
|
|
||||||
// Initialize cheat engine
|
// Initialize cheat engine
|
||||||
if (cheat_engine) {
|
if (cheat_engine) {
|
||||||
@ -425,6 +426,7 @@ struct System::Impl {
|
|||||||
cpu_manager.Shutdown();
|
cpu_manager.Shutdown();
|
||||||
debugger.reset();
|
debugger.reset();
|
||||||
kernel.Shutdown();
|
kernel.Shutdown();
|
||||||
|
memory.Reset();
|
||||||
Network::RestartSocketOperations();
|
Network::RestartSocketOperations();
|
||||||
|
|
||||||
if (auto room_member = room_network.GetRoomMember().lock()) {
|
if (auto room_member = room_network.GetRoomMember().lock()) {
|
||||||
@ -505,6 +507,7 @@ struct System::Impl {
|
|||||||
std::unique_ptr<Tegra::Host1x::Host1x> host1x_core;
|
std::unique_ptr<Tegra::Host1x::Host1x> host1x_core;
|
||||||
std::unique_ptr<Core::DeviceMemory> device_memory;
|
std::unique_ptr<Core::DeviceMemory> device_memory;
|
||||||
std::unique_ptr<AudioCore::AudioCore> audio_core;
|
std::unique_ptr<AudioCore::AudioCore> audio_core;
|
||||||
|
Core::Memory::Memory memory;
|
||||||
Core::HID::HIDCore hid_core;
|
Core::HID::HIDCore hid_core;
|
||||||
Network::RoomNetwork room_network;
|
Network::RoomNetwork room_network;
|
||||||
|
|
||||||
@ -564,6 +567,9 @@ struct System::Impl {
|
|||||||
std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};
|
std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};
|
||||||
std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_cpu{};
|
std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_cpu{};
|
||||||
|
|
||||||
|
std::array<Core::GPUDirtyMemoryManager, Core::Hardware::NUM_CPU_CORES>
|
||||||
|
gpu_dirty_memory_write_manager{};
|
||||||
|
|
||||||
std::deque<std::vector<u8>> user_channel;
|
std::deque<std::vector<u8>> user_channel;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -646,12 +652,29 @@ void System::PrepareReschedule(const u32 core_index) {
|
|||||||
impl->kernel.PrepareReschedule(core_index);
|
impl->kernel.PrepareReschedule(core_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Core::GPUDirtyMemoryManager& System::CurrentGPUDirtyMemoryManager() {
|
||||||
|
const std::size_t core = impl->kernel.GetCurrentHostThreadID();
|
||||||
|
return impl->gpu_dirty_memory_write_manager[core < Core::Hardware::NUM_CPU_CORES
|
||||||
|
? core
|
||||||
|
: Core::Hardware::NUM_CPU_CORES - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Provides a constant reference to the current gou dirty memory manager.
|
||||||
|
const Core::GPUDirtyMemoryManager& System::CurrentGPUDirtyMemoryManager() const {
|
||||||
|
const std::size_t core = impl->kernel.GetCurrentHostThreadID();
|
||||||
|
return impl->gpu_dirty_memory_write_manager[core < Core::Hardware::NUM_CPU_CORES
|
||||||
|
? core
|
||||||
|
: Core::Hardware::NUM_CPU_CORES - 1];
|
||||||
|
}
|
||||||
|
|
||||||
size_t System::GetCurrentHostThreadID() const {
|
size_t System::GetCurrentHostThreadID() const {
|
||||||
return impl->kernel.GetCurrentHostThreadID();
|
return impl->kernel.GetCurrentHostThreadID();
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback) {
|
void System::GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback) {
|
||||||
return this->ApplicationProcess()->GatherGPUDirtyMemory(callback);
|
for (auto& manager : impl->gpu_dirty_memory_write_manager) {
|
||||||
|
manager.Gather(callback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PerfStatsResults System::GetAndResetPerfStats() {
|
PerfStatsResults System::GetAndResetPerfStats() {
|
||||||
@ -700,12 +723,20 @@ const Kernel::KProcess* System::ApplicationProcess() const {
|
|||||||
return impl->kernel.ApplicationProcess();
|
return impl->kernel.ApplicationProcess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExclusiveMonitor& System::Monitor() {
|
||||||
|
return impl->kernel.GetExclusiveMonitor();
|
||||||
|
}
|
||||||
|
|
||||||
|
const ExclusiveMonitor& System::Monitor() const {
|
||||||
|
return impl->kernel.GetExclusiveMonitor();
|
||||||
|
}
|
||||||
|
|
||||||
Memory::Memory& System::ApplicationMemory() {
|
Memory::Memory& System::ApplicationMemory() {
|
||||||
return impl->kernel.ApplicationProcess()->GetMemory();
|
return impl->memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Core::Memory::Memory& System::ApplicationMemory() const {
|
const Core::Memory::Memory& System::ApplicationMemory() const {
|
||||||
return impl->kernel.ApplicationProcess()->GetMemory();
|
return impl->memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
Tegra::GPU& System::GPU() {
|
Tegra::GPU& System::GPU() {
|
||||||
|
@ -116,6 +116,7 @@ class CpuManager;
|
|||||||
class Debugger;
|
class Debugger;
|
||||||
class DeviceMemory;
|
class DeviceMemory;
|
||||||
class ExclusiveMonitor;
|
class ExclusiveMonitor;
|
||||||
|
class GPUDirtyMemoryManager;
|
||||||
class PerfStats;
|
class PerfStats;
|
||||||
class Reporter;
|
class Reporter;
|
||||||
class SpeedLimiter;
|
class SpeedLimiter;
|
||||||
@ -224,6 +225,12 @@ public:
|
|||||||
/// Prepare the core emulation for a reschedule
|
/// Prepare the core emulation for a reschedule
|
||||||
void PrepareReschedule(u32 core_index);
|
void PrepareReschedule(u32 core_index);
|
||||||
|
|
||||||
|
/// Provides a reference to the gou dirty memory manager.
|
||||||
|
[[nodiscard]] Core::GPUDirtyMemoryManager& CurrentGPUDirtyMemoryManager();
|
||||||
|
|
||||||
|
/// Provides a constant reference to the current gou dirty memory manager.
|
||||||
|
[[nodiscard]] const Core::GPUDirtyMemoryManager& CurrentGPUDirtyMemoryManager() const;
|
||||||
|
|
||||||
void GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback);
|
void GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback);
|
||||||
|
|
||||||
[[nodiscard]] size_t GetCurrentHostThreadID() const;
|
[[nodiscard]] size_t GetCurrentHostThreadID() const;
|
||||||
@ -243,6 +250,12 @@ public:
|
|||||||
/// Gets a const reference to the underlying CPU manager
|
/// Gets a const reference to the underlying CPU manager
|
||||||
[[nodiscard]] const CpuManager& GetCpuManager() const;
|
[[nodiscard]] const CpuManager& GetCpuManager() const;
|
||||||
|
|
||||||
|
/// Gets a reference to the exclusive monitor
|
||||||
|
[[nodiscard]] ExclusiveMonitor& Monitor();
|
||||||
|
|
||||||
|
/// Gets a constant reference to the exclusive monitor
|
||||||
|
[[nodiscard]] const ExclusiveMonitor& Monitor() const;
|
||||||
|
|
||||||
/// Gets a mutable reference to the system memory instance.
|
/// Gets a mutable reference to the system memory instance.
|
||||||
[[nodiscard]] Core::Memory::Memory& ApplicationMemory();
|
[[nodiscard]] Core::Memory::Memory& ApplicationMemory();
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callbac
|
|||||||
struct CoreTiming::Event {
|
struct CoreTiming::Event {
|
||||||
s64 time;
|
s64 time;
|
||||||
u64 fifo_order;
|
u64 fifo_order;
|
||||||
|
std::uintptr_t user_data;
|
||||||
std::weak_ptr<EventType> type;
|
std::weak_ptr<EventType> type;
|
||||||
s64 reschedule_time;
|
s64 reschedule_time;
|
||||||
heap_t::handle_type handle{};
|
heap_t::handle_type handle{};
|
||||||
@ -66,15 +67,17 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) {
|
|||||||
event_fifo_id = 0;
|
event_fifo_id = 0;
|
||||||
shutting_down = false;
|
shutting_down = false;
|
||||||
cpu_ticks = 0;
|
cpu_ticks = 0;
|
||||||
|
const auto empty_timed_callback = [](std::uintptr_t, u64, std::chrono::nanoseconds)
|
||||||
|
-> std::optional<std::chrono::nanoseconds> { return std::nullopt; };
|
||||||
|
ev_lost = CreateEvent("_lost_event", empty_timed_callback);
|
||||||
if (is_multicore) {
|
if (is_multicore) {
|
||||||
timer_thread = std::make_unique<std::jthread>(ThreadEntry, std::ref(*this));
|
timer_thread = std::make_unique<std::jthread>(ThreadEntry, std::ref(*this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreTiming::ClearPendingEvents() {
|
void CoreTiming::ClearPendingEvents() {
|
||||||
std::scoped_lock lock{advance_lock, basic_lock};
|
std::scoped_lock lock{basic_lock};
|
||||||
event_queue.clear();
|
event_queue.clear();
|
||||||
event.Set();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreTiming::Pause(bool is_paused) {
|
void CoreTiming::Pause(bool is_paused) {
|
||||||
@ -116,12 +119,14 @@ bool CoreTiming::HasPendingEvents() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future,
|
void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future,
|
||||||
const std::shared_ptr<EventType>& event_type, bool absolute_time) {
|
const std::shared_ptr<EventType>& event_type,
|
||||||
|
std::uintptr_t user_data, bool absolute_time) {
|
||||||
{
|
{
|
||||||
std::scoped_lock scope{basic_lock};
|
std::scoped_lock scope{basic_lock};
|
||||||
const auto next_time{absolute_time ? ns_into_future : GetGlobalTimeNs() + ns_into_future};
|
const auto next_time{absolute_time ? ns_into_future : GetGlobalTimeNs() + ns_into_future};
|
||||||
|
|
||||||
auto h{event_queue.emplace(Event{next_time.count(), event_fifo_id++, event_type, 0})};
|
auto h{event_queue.emplace(
|
||||||
|
Event{next_time.count(), event_fifo_id++, user_data, event_type, 0})};
|
||||||
(*h).handle = h;
|
(*h).handle = h;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,13 +136,13 @@ void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future,
|
|||||||
void CoreTiming::ScheduleLoopingEvent(std::chrono::nanoseconds start_time,
|
void CoreTiming::ScheduleLoopingEvent(std::chrono::nanoseconds start_time,
|
||||||
std::chrono::nanoseconds resched_time,
|
std::chrono::nanoseconds resched_time,
|
||||||
const std::shared_ptr<EventType>& event_type,
|
const std::shared_ptr<EventType>& event_type,
|
||||||
bool absolute_time) {
|
std::uintptr_t user_data, bool absolute_time) {
|
||||||
{
|
{
|
||||||
std::scoped_lock scope{basic_lock};
|
std::scoped_lock scope{basic_lock};
|
||||||
const auto next_time{absolute_time ? start_time : GetGlobalTimeNs() + start_time};
|
const auto next_time{absolute_time ? start_time : GetGlobalTimeNs() + start_time};
|
||||||
|
|
||||||
auto h{event_queue.emplace(
|
auto h{event_queue.emplace(Event{next_time.count(), event_fifo_id++, user_data, event_type,
|
||||||
Event{next_time.count(), event_fifo_id++, event_type, resched_time.count()})};
|
resched_time.count()})};
|
||||||
(*h).handle = h;
|
(*h).handle = h;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,14 +150,14 @@ void CoreTiming::ScheduleLoopingEvent(std::chrono::nanoseconds start_time,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
|
void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
|
||||||
UnscheduleEventType type) {
|
std::uintptr_t user_data, bool wait) {
|
||||||
{
|
{
|
||||||
std::scoped_lock lk{basic_lock};
|
std::scoped_lock lk{basic_lock};
|
||||||
|
|
||||||
std::vector<heap_t::handle_type> to_remove;
|
std::vector<heap_t::handle_type> to_remove;
|
||||||
for (auto itr = event_queue.begin(); itr != event_queue.end(); itr++) {
|
for (auto itr = event_queue.begin(); itr != event_queue.end(); itr++) {
|
||||||
const Event& e = *itr;
|
const Event& e = *itr;
|
||||||
if (e.type.lock().get() == event_type.get()) {
|
if (e.type.lock().get() == event_type.get() && e.user_data == user_data) {
|
||||||
to_remove.push_back(itr->handle);
|
to_remove.push_back(itr->handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -160,12 +165,10 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
|
|||||||
for (auto h : to_remove) {
|
for (auto h : to_remove) {
|
||||||
event_queue.erase(h);
|
event_queue.erase(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
event_type->sequence_number++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Force any in-progress events to finish
|
// Force any in-progress events to finish
|
||||||
if (type == UnscheduleEventType::Wait) {
|
if (wait) {
|
||||||
std::scoped_lock lk{advance_lock};
|
std::scoped_lock lk{advance_lock};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -205,31 +208,28 @@ std::optional<s64> CoreTiming::Advance() {
|
|||||||
const Event& evt = event_queue.top();
|
const Event& evt = event_queue.top();
|
||||||
|
|
||||||
if (const auto event_type{evt.type.lock()}) {
|
if (const auto event_type{evt.type.lock()}) {
|
||||||
const auto evt_time = evt.time;
|
|
||||||
const auto evt_sequence_num = event_type->sequence_number;
|
|
||||||
|
|
||||||
if (evt.reschedule_time == 0) {
|
if (evt.reschedule_time == 0) {
|
||||||
|
const auto evt_user_data = evt.user_data;
|
||||||
|
const auto evt_time = evt.time;
|
||||||
|
|
||||||
event_queue.pop();
|
event_queue.pop();
|
||||||
|
|
||||||
basic_lock.unlock();
|
basic_lock.unlock();
|
||||||
|
|
||||||
event_type->callback(
|
event_type->callback(
|
||||||
evt_time, std::chrono::nanoseconds{GetGlobalTimeNs().count() - evt_time});
|
evt_user_data, evt_time,
|
||||||
|
std::chrono::nanoseconds{GetGlobalTimeNs().count() - evt_time});
|
||||||
|
|
||||||
basic_lock.lock();
|
basic_lock.lock();
|
||||||
} else {
|
} else {
|
||||||
basic_lock.unlock();
|
basic_lock.unlock();
|
||||||
|
|
||||||
const auto new_schedule_time{event_type->callback(
|
const auto new_schedule_time{event_type->callback(
|
||||||
evt_time, std::chrono::nanoseconds{GetGlobalTimeNs().count() - evt_time})};
|
evt.user_data, evt.time,
|
||||||
|
std::chrono::nanoseconds{GetGlobalTimeNs().count() - evt.time})};
|
||||||
|
|
||||||
basic_lock.lock();
|
basic_lock.lock();
|
||||||
|
|
||||||
if (evt_sequence_num != event_type->sequence_number) {
|
|
||||||
// Heap handle is invalidated after external modification.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto next_schedule_time{new_schedule_time.has_value()
|
const auto next_schedule_time{new_schedule_time.has_value()
|
||||||
? new_schedule_time.value().count()
|
? new_schedule_time.value().count()
|
||||||
: evt.reschedule_time};
|
: evt.reschedule_time};
|
||||||
@ -241,8 +241,8 @@ std::optional<s64> CoreTiming::Advance() {
|
|||||||
next_time = pause_end_time + next_schedule_time;
|
next_time = pause_end_time + next_schedule_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
event_queue.update(evt.handle, Event{next_time, event_fifo_id++, evt.type,
|
event_queue.update(evt.handle, Event{next_time, event_fifo_id++, evt.user_data,
|
||||||
next_schedule_time, evt.handle});
|
evt.type, next_schedule_time, evt.handle});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,25 +22,17 @@ namespace Core::Timing {
|
|||||||
|
|
||||||
/// A callback that may be scheduled for a particular core timing event.
|
/// A callback that may be scheduled for a particular core timing event.
|
||||||
using TimedCallback = std::function<std::optional<std::chrono::nanoseconds>(
|
using TimedCallback = std::function<std::optional<std::chrono::nanoseconds>(
|
||||||
s64 time, std::chrono::nanoseconds ns_late)>;
|
std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)>;
|
||||||
|
|
||||||
/// Contains the characteristics of a particular event.
|
/// Contains the characteristics of a particular event.
|
||||||
struct EventType {
|
struct EventType {
|
||||||
explicit EventType(TimedCallback&& callback_, std::string&& name_)
|
explicit EventType(TimedCallback&& callback_, std::string&& name_)
|
||||||
: callback{std::move(callback_)}, name{std::move(name_)}, sequence_number{0} {}
|
: callback{std::move(callback_)}, name{std::move(name_)} {}
|
||||||
|
|
||||||
/// The event's callback function.
|
/// The event's callback function.
|
||||||
TimedCallback callback;
|
TimedCallback callback;
|
||||||
/// A pointer to the name of the event.
|
/// A pointer to the name of the event.
|
||||||
const std::string name;
|
const std::string name;
|
||||||
/// A monotonic sequence number, incremented when this event is
|
|
||||||
/// changed externally.
|
|
||||||
size_t sequence_number;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class UnscheduleEventType {
|
|
||||||
Wait,
|
|
||||||
NoWait,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -97,17 +89,23 @@ public:
|
|||||||
|
|
||||||
/// Schedules an event in core timing
|
/// Schedules an event in core timing
|
||||||
void ScheduleEvent(std::chrono::nanoseconds ns_into_future,
|
void ScheduleEvent(std::chrono::nanoseconds ns_into_future,
|
||||||
const std::shared_ptr<EventType>& event_type, bool absolute_time = false);
|
const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data = 0,
|
||||||
|
bool absolute_time = false);
|
||||||
|
|
||||||
/// Schedules an event which will automatically re-schedule itself with the given time, until
|
/// Schedules an event which will automatically re-schedule itself with the given time, until
|
||||||
/// unscheduled
|
/// unscheduled
|
||||||
void ScheduleLoopingEvent(std::chrono::nanoseconds start_time,
|
void ScheduleLoopingEvent(std::chrono::nanoseconds start_time,
|
||||||
std::chrono::nanoseconds resched_time,
|
std::chrono::nanoseconds resched_time,
|
||||||
const std::shared_ptr<EventType>& event_type,
|
const std::shared_ptr<EventType>& event_type,
|
||||||
bool absolute_time = false);
|
std::uintptr_t user_data = 0, bool absolute_time = false);
|
||||||
|
|
||||||
void UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
|
void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data,
|
||||||
UnscheduleEventType type = UnscheduleEventType::Wait);
|
bool wait = true);
|
||||||
|
|
||||||
|
void UnscheduleEventWithoutWait(const std::shared_ptr<EventType>& event_type,
|
||||||
|
std::uintptr_t user_data) {
|
||||||
|
UnscheduleEvent(event_type, user_data, false);
|
||||||
|
}
|
||||||
|
|
||||||
void AddTicks(u64 ticks_to_add);
|
void AddTicks(u64 ticks_to_add);
|
||||||
|
|
||||||
@ -160,6 +158,7 @@ private:
|
|||||||
heap_t event_queue;
|
heap_t event_queue;
|
||||||
u64 event_fifo_id = 0;
|
u64 event_fifo_id = 0;
|
||||||
|
|
||||||
|
std::shared_ptr<EventType> ev_lost;
|
||||||
Common::Event event{};
|
Common::Event event{};
|
||||||
Common::Event pause_event{};
|
Common::Event pause_event{};
|
||||||
mutable std::mutex basic_lock;
|
mutable std::mutex basic_lock;
|
||||||
|
@ -73,9 +73,6 @@ VirtualFile PatchIPS(const VirtualFile& in, const VirtualFile& ips) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
auto in_data = in->ReadAllBytes();
|
auto in_data = in->ReadAllBytes();
|
||||||
if (in_data.size() == 0) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<u8> temp(type == IPSFileType::IPS ? 3 : 4);
|
std::vector<u8> temp(type == IPSFileType::IPS ? 3 : 4);
|
||||||
u64 offset = 5; // After header
|
u64 offset = 5; // After header
|
||||||
@ -91,10 +88,6 @@ VirtualFile PatchIPS(const VirtualFile& in, const VirtualFile& ips) {
|
|||||||
else
|
else
|
||||||
real_offset = (temp[0] << 16) | (temp[1] << 8) | temp[2];
|
real_offset = (temp[0] << 16) | (temp[1] << 8) | temp[2];
|
||||||
|
|
||||||
if (real_offset > in_data.size()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
u16 data_size{};
|
u16 data_size{};
|
||||||
if (ips->ReadObject(&data_size, offset) != sizeof(u16))
|
if (ips->ReadObject(&data_size, offset) != sizeof(u16))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -166,10 +166,6 @@ u32 ProgramMetadata::GetSystemResourceSize() const {
|
|||||||
return npdm_header.system_resource_size;
|
return npdm_header.system_resource_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
PoolPartition ProgramMetadata::GetPoolPartition() const {
|
|
||||||
return acid_header.pool_partition;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ProgramMetadata::KernelCapabilityDescriptors& ProgramMetadata::GetKernelCapabilities() const {
|
const ProgramMetadata::KernelCapabilityDescriptors& ProgramMetadata::GetKernelCapabilities() const {
|
||||||
return aci_kernel_capabilities;
|
return aci_kernel_capabilities;
|
||||||
}
|
}
|
||||||
@ -205,7 +201,7 @@ void ProgramMetadata::Print() const {
|
|||||||
// Begin ACID printing (potential perms, signed)
|
// Begin ACID printing (potential perms, signed)
|
||||||
LOG_DEBUG(Service_FS, "Magic: {:.4}", acid_header.magic.data());
|
LOG_DEBUG(Service_FS, "Magic: {:.4}", acid_header.magic.data());
|
||||||
LOG_DEBUG(Service_FS, "Flags: 0x{:02X}", acid_header.flags);
|
LOG_DEBUG(Service_FS, "Flags: 0x{:02X}", acid_header.flags);
|
||||||
LOG_DEBUG(Service_FS, " > Is Retail: {}", acid_header.production_flag ? "YES" : "NO");
|
LOG_DEBUG(Service_FS, " > Is Retail: {}", acid_header.is_retail ? "YES" : "NO");
|
||||||
LOG_DEBUG(Service_FS, "Title ID Min: 0x{:016X}", acid_header.title_id_min);
|
LOG_DEBUG(Service_FS, "Title ID Min: 0x{:016X}", acid_header.title_id_min);
|
||||||
LOG_DEBUG(Service_FS, "Title ID Max: 0x{:016X}", acid_header.title_id_max);
|
LOG_DEBUG(Service_FS, "Title ID Max: 0x{:016X}", acid_header.title_id_max);
|
||||||
LOG_DEBUG(Service_FS, "Filesystem Access: 0x{:016X}\n", acid_file_access.permissions);
|
LOG_DEBUG(Service_FS, "Filesystem Access: 0x{:016X}\n", acid_file_access.permissions);
|
||||||
|
@ -34,13 +34,6 @@ enum class ProgramFilePermission : u64 {
|
|||||||
Everything = 1ULL << 63,
|
Everything = 1ULL << 63,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class PoolPartition : u32 {
|
|
||||||
Application = 0,
|
|
||||||
Applet = 1,
|
|
||||||
System = 2,
|
|
||||||
SystemNonSecure = 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper which implements an interface to parse Program Description Metadata (NPDM)
|
* Helper which implements an interface to parse Program Description Metadata (NPDM)
|
||||||
* Data can either be loaded from a file path or with data and an offset into it.
|
* Data can either be loaded from a file path or with data and an offset into it.
|
||||||
@ -79,7 +72,6 @@ public:
|
|||||||
u64 GetTitleID() const;
|
u64 GetTitleID() const;
|
||||||
u64 GetFilesystemPermissions() const;
|
u64 GetFilesystemPermissions() const;
|
||||||
u32 GetSystemResourceSize() const;
|
u32 GetSystemResourceSize() const;
|
||||||
PoolPartition GetPoolPartition() const;
|
|
||||||
const KernelCapabilityDescriptors& GetKernelCapabilities() const;
|
const KernelCapabilityDescriptors& GetKernelCapabilities() const;
|
||||||
const std::array<u8, 0x10>& GetName() const {
|
const std::array<u8, 0x10>& GetName() const {
|
||||||
return npdm_header.application_name;
|
return npdm_header.application_name;
|
||||||
@ -124,9 +116,8 @@ private:
|
|||||||
union {
|
union {
|
||||||
u32 flags;
|
u32 flags;
|
||||||
|
|
||||||
BitField<0, 1, u32> production_flag;
|
BitField<0, 1, u32> is_retail;
|
||||||
BitField<1, 1, u32> unqualified_approval;
|
BitField<1, 31, u32> flags_unk;
|
||||||
BitField<2, 4, PoolPartition> pool_partition;
|
|
||||||
};
|
};
|
||||||
u64_le title_id_min;
|
u64_le title_id_min;
|
||||||
u64_le title_id_max;
|
u64_le title_id_max;
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
#include "core/arm/exclusive_monitor.h"
|
#include "core/arm/exclusive_monitor.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/hle/kernel/k_address_arbiter.h"
|
#include "core/hle/kernel/k_address_arbiter.h"
|
||||||
#include "core/hle/kernel/k_process.h"
|
|
||||||
#include "core/hle/kernel/k_scheduler.h"
|
#include "core/hle/kernel/k_scheduler.h"
|
||||||
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
#include "core/hle/kernel/k_thread.h"
|
||||||
@ -27,9 +26,9 @@ bool ReadFromUser(KernelCore& kernel, s32* out, KProcessAddress address) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DecrementIfLessThan(KernelCore& kernel, s32* out, KProcessAddress address, s32 value) {
|
bool DecrementIfLessThan(Core::System& system, s32* out, KProcessAddress address, s32 value) {
|
||||||
auto& monitor = GetCurrentProcess(kernel).GetExclusiveMonitor();
|
auto& monitor = system.Monitor();
|
||||||
const auto current_core = kernel.CurrentPhysicalCoreIndex();
|
const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();
|
||||||
|
|
||||||
// NOTE: If scheduler lock is not held here, interrupt disable is required.
|
// NOTE: If scheduler lock is not held here, interrupt disable is required.
|
||||||
// KScopedInterruptDisable di;
|
// KScopedInterruptDisable di;
|
||||||
@ -67,10 +66,10 @@ bool DecrementIfLessThan(KernelCore& kernel, s32* out, KProcessAddress address,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UpdateIfEqual(KernelCore& kernel, s32* out, KProcessAddress address, s32 value,
|
bool UpdateIfEqual(Core::System& system, s32* out, KProcessAddress address, s32 value,
|
||||||
s32 new_value) {
|
s32 new_value) {
|
||||||
auto& monitor = GetCurrentProcess(kernel).GetExclusiveMonitor();
|
auto& monitor = system.Monitor();
|
||||||
const auto current_core = kernel.CurrentPhysicalCoreIndex();
|
const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();
|
||||||
|
|
||||||
// NOTE: If scheduler lock is not held here, interrupt disable is required.
|
// NOTE: If scheduler lock is not held here, interrupt disable is required.
|
||||||
// KScopedInterruptDisable di;
|
// KScopedInterruptDisable di;
|
||||||
@ -160,7 +159,7 @@ Result KAddressArbiter::SignalAndIncrementIfEqual(uint64_t addr, s32 value, s32
|
|||||||
|
|
||||||
// Check the userspace value.
|
// Check the userspace value.
|
||||||
s32 user_value{};
|
s32 user_value{};
|
||||||
R_UNLESS(UpdateIfEqual(m_kernel, std::addressof(user_value), addr, value, value + 1),
|
R_UNLESS(UpdateIfEqual(m_system, std::addressof(user_value), addr, value, value + 1),
|
||||||
ResultInvalidCurrentMemory);
|
ResultInvalidCurrentMemory);
|
||||||
R_UNLESS(user_value == value, ResultInvalidState);
|
R_UNLESS(user_value == value, ResultInvalidState);
|
||||||
|
|
||||||
@ -220,7 +219,7 @@ Result KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(uint64_t addr, s32
|
|||||||
s32 user_value{};
|
s32 user_value{};
|
||||||
bool succeeded{};
|
bool succeeded{};
|
||||||
if (value != new_value) {
|
if (value != new_value) {
|
||||||
succeeded = UpdateIfEqual(m_kernel, std::addressof(user_value), addr, value, new_value);
|
succeeded = UpdateIfEqual(m_system, std::addressof(user_value), addr, value, new_value);
|
||||||
} else {
|
} else {
|
||||||
succeeded = ReadFromUser(m_kernel, std::addressof(user_value), addr);
|
succeeded = ReadFromUser(m_kernel, std::addressof(user_value), addr);
|
||||||
}
|
}
|
||||||
@ -263,7 +262,7 @@ Result KAddressArbiter::WaitIfLessThan(uint64_t addr, s32 value, bool decrement,
|
|||||||
s32 user_value{};
|
s32 user_value{};
|
||||||
bool succeeded{};
|
bool succeeded{};
|
||||||
if (decrement) {
|
if (decrement) {
|
||||||
succeeded = DecrementIfLessThan(m_kernel, std::addressof(user_value), addr, value);
|
succeeded = DecrementIfLessThan(m_system, std::addressof(user_value), addr, value);
|
||||||
} else {
|
} else {
|
||||||
succeeded = ReadFromUser(m_kernel, std::addressof(user_value), addr);
|
succeeded = ReadFromUser(m_kernel, std::addressof(user_value), addr);
|
||||||
}
|
}
|
||||||
|
@ -8,22 +8,19 @@
|
|||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
void KAutoObjectWithListContainer::Register(KAutoObjectWithList* obj) {
|
void KAutoObjectWithListContainer::Register(KAutoObjectWithList* obj) {
|
||||||
// KScopedInterruptDisable di;
|
KScopedLightLock lk(m_lock);
|
||||||
KScopedSpinLock lk(m_lock);
|
|
||||||
|
|
||||||
m_object_list.insert_unique(*obj);
|
m_object_list.insert_unique(*obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
void KAutoObjectWithListContainer::Unregister(KAutoObjectWithList* obj) {
|
void KAutoObjectWithListContainer::Unregister(KAutoObjectWithList* obj) {
|
||||||
// KScopedInterruptDisable di;
|
KScopedLightLock lk(m_lock);
|
||||||
KScopedSpinLock lk(m_lock);
|
|
||||||
|
|
||||||
m_object_list.erase(*obj);
|
m_object_list.erase(*obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t KAutoObjectWithListContainer::GetOwnedCount(KProcess* owner) {
|
size_t KAutoObjectWithListContainer::GetOwnedCount(KProcess* owner) {
|
||||||
// KScopedInterruptDisable di;
|
KScopedLightLock lk(m_lock);
|
||||||
KScopedSpinLock lk(m_lock);
|
|
||||||
|
|
||||||
return std::count_if(m_object_list.begin(), m_object_list.end(),
|
return std::count_if(m_object_list.begin(), m_object_list.end(),
|
||||||
[&](const auto& obj) { return obj.GetOwner() == owner; });
|
[&](const auto& obj) { return obj.GetOwner() == owner; });
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "core/hle/kernel/k_auto_object.h"
|
#include "core/hle/kernel/k_auto_object.h"
|
||||||
#include "core/hle/kernel/k_spin_lock.h"
|
#include "core/hle/kernel/k_light_lock.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
@ -21,7 +21,32 @@ public:
|
|||||||
|
|
||||||
using ListType = boost::intrusive::rbtree<KAutoObjectWithList>;
|
using ListType = boost::intrusive::rbtree<KAutoObjectWithList>;
|
||||||
|
|
||||||
KAutoObjectWithListContainer(KernelCore& kernel) : m_lock(), m_object_list() {}
|
class ListAccessor : public KScopedLightLock {
|
||||||
|
public:
|
||||||
|
explicit ListAccessor(KAutoObjectWithListContainer* container)
|
||||||
|
: KScopedLightLock(container->m_lock), m_list(container->m_object_list) {}
|
||||||
|
explicit ListAccessor(KAutoObjectWithListContainer& container)
|
||||||
|
: KScopedLightLock(container.m_lock), m_list(container.m_object_list) {}
|
||||||
|
|
||||||
|
typename ListType::iterator begin() const {
|
||||||
|
return m_list.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
typename ListType::iterator end() const {
|
||||||
|
return m_list.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
typename ListType::iterator find(typename ListType::const_reference ref) const {
|
||||||
|
return m_list.find(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ListType& m_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
friend class ListAccessor;
|
||||||
|
|
||||||
|
KAutoObjectWithListContainer(KernelCore& kernel) : m_lock(kernel), m_object_list() {}
|
||||||
|
|
||||||
void Initialize() {}
|
void Initialize() {}
|
||||||
void Finalize() {}
|
void Finalize() {}
|
||||||
@ -31,7 +56,7 @@ public:
|
|||||||
size_t GetOwnedCount(KProcess* owner);
|
size_t GetOwnedCount(KProcess* owner);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
KSpinLock m_lock;
|
KLightLock m_lock;
|
||||||
ListType m_object_list;
|
ListType m_object_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -185,10 +185,6 @@ Result KCapabilities::ProcessMapRegionCapability(const u32 cap, F f) {
|
|||||||
case RegionType::NoMapping:
|
case RegionType::NoMapping:
|
||||||
break;
|
break;
|
||||||
case RegionType::KernelTraceBuffer:
|
case RegionType::KernelTraceBuffer:
|
||||||
if constexpr (!IsKTraceEnabled) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
[[fallthrough]];
|
|
||||||
case RegionType::OnMemoryBootImage:
|
case RegionType::OnMemoryBootImage:
|
||||||
case RegionType::DTB:
|
case RegionType::DTB:
|
||||||
R_TRY(f(MemoryRegions[static_cast<u32>(type)], perm));
|
R_TRY(f(MemoryRegions[static_cast<u32>(type)], perm));
|
||||||
@ -334,6 +330,8 @@ Result KCapabilities::SetCapabilities(std::span<const u32> caps, KProcessPageTab
|
|||||||
|
|
||||||
// Map the range.
|
// Map the range.
|
||||||
R_TRY(this->MapRange_(cap, size_cap, page_table));
|
R_TRY(this->MapRange_(cap, size_cap, page_table));
|
||||||
|
} else if (GetCapabilityType(cap) == CapabilityType::MapRegion && !IsKTraceEnabled) {
|
||||||
|
continue;
|
||||||
} else {
|
} else {
|
||||||
R_TRY(this->SetCapability(cap, set_flags, set_svc, page_table));
|
R_TRY(this->SetCapability(cap, set_flags, set_svc, page_table));
|
||||||
}
|
}
|
||||||
|
@ -58,8 +58,9 @@ Result KClientPort::CreateSession(KClientSession** out) {
|
|||||||
KSession* session{};
|
KSession* session{};
|
||||||
|
|
||||||
// Reserve a new session from the resource limit.
|
// Reserve a new session from the resource limit.
|
||||||
KScopedResourceReservation session_reservation(GetCurrentProcessPointer(m_kernel),
|
//! FIXME: we are reserving this from the wrong resource limit!
|
||||||
LimitableResource::SessionCountMax);
|
KScopedResourceReservation session_reservation(
|
||||||
|
m_kernel.ApplicationProcess()->GetResourceLimit(), LimitableResource::SessionCountMax);
|
||||||
R_UNLESS(session_reservation.Succeeded(), ResultLimitReached);
|
R_UNLESS(session_reservation.Succeeded(), ResultLimitReached);
|
||||||
|
|
||||||
// Allocate a session normally.
|
// Allocate a session normally.
|
||||||
|
@ -28,10 +28,10 @@ bool WriteToUser(KernelCore& kernel, KProcessAddress address, const u32* p) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UpdateLockAtomic(KernelCore& kernel, u32* out, KProcessAddress address, u32 if_zero,
|
bool UpdateLockAtomic(Core::System& system, u32* out, KProcessAddress address, u32 if_zero,
|
||||||
u32 new_orr_mask) {
|
u32 new_orr_mask) {
|
||||||
auto& monitor = GetCurrentProcess(kernel).GetExclusiveMonitor();
|
auto& monitor = system.Monitor();
|
||||||
const auto current_core = kernel.CurrentPhysicalCoreIndex();
|
const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();
|
||||||
|
|
||||||
u32 expected{};
|
u32 expected{};
|
||||||
|
|
||||||
@ -208,7 +208,7 @@ void KConditionVariable::SignalImpl(KThread* thread) {
|
|||||||
// TODO(bunnei): We should call CanAccessAtomic(..) here.
|
// TODO(bunnei): We should call CanAccessAtomic(..) here.
|
||||||
can_access = true;
|
can_access = true;
|
||||||
if (can_access) [[likely]] {
|
if (can_access) [[likely]] {
|
||||||
UpdateLockAtomic(m_kernel, std::addressof(prev_tag), address, own_tag,
|
UpdateLockAtomic(m_system, std::addressof(prev_tag), address, own_tag,
|
||||||
Svc::HandleWaitMask);
|
Svc::HandleWaitMask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,7 +90,8 @@ public:
|
|||||||
// Handle pseudo-handles.
|
// Handle pseudo-handles.
|
||||||
if constexpr (std::derived_from<KProcess, T>) {
|
if constexpr (std::derived_from<KProcess, T>) {
|
||||||
if (handle == Svc::PseudoHandle::CurrentProcess) {
|
if (handle == Svc::PseudoHandle::CurrentProcess) {
|
||||||
auto* const cur_process = GetCurrentProcessPointer(m_kernel);
|
//! FIXME: this is the wrong process!
|
||||||
|
auto* const cur_process = m_kernel.ApplicationProcess();
|
||||||
ASSERT(cur_process != nullptr);
|
ASSERT(cur_process != nullptr);
|
||||||
return cur_process;
|
return cur_process;
|
||||||
}
|
}
|
||||||
|
@ -10,15 +10,15 @@ namespace Kernel {
|
|||||||
|
|
||||||
void KHardwareTimer::Initialize() {
|
void KHardwareTimer::Initialize() {
|
||||||
// Create the timing callback to register with CoreTiming.
|
// Create the timing callback to register with CoreTiming.
|
||||||
m_event_type = Core::Timing::CreateEvent("KHardwareTimer::Callback",
|
m_event_type = Core::Timing::CreateEvent(
|
||||||
[this](s64, std::chrono::nanoseconds) {
|
"KHardwareTimer::Callback", [](std::uintptr_t timer_handle, s64, std::chrono::nanoseconds) {
|
||||||
this->DoTask();
|
reinterpret_cast<KHardwareTimer*>(timer_handle)->DoTask();
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void KHardwareTimer::Finalize() {
|
void KHardwareTimer::Finalize() {
|
||||||
m_kernel.System().CoreTiming().UnscheduleEvent(m_event_type);
|
m_kernel.System().CoreTiming().UnscheduleEvent(m_event_type, reinterpret_cast<uintptr_t>(this));
|
||||||
m_wakeup_time = std::numeric_limits<s64>::max();
|
m_wakeup_time = std::numeric_limits<s64>::max();
|
||||||
m_event_type.reset();
|
m_event_type.reset();
|
||||||
}
|
}
|
||||||
@ -57,12 +57,13 @@ void KHardwareTimer::EnableInterrupt(s64 wakeup_time) {
|
|||||||
|
|
||||||
m_wakeup_time = wakeup_time;
|
m_wakeup_time = wakeup_time;
|
||||||
m_kernel.System().CoreTiming().ScheduleEvent(std::chrono::nanoseconds{m_wakeup_time},
|
m_kernel.System().CoreTiming().ScheduleEvent(std::chrono::nanoseconds{m_wakeup_time},
|
||||||
m_event_type, true);
|
m_event_type, reinterpret_cast<uintptr_t>(this),
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void KHardwareTimer::DisableInterrupt() {
|
void KHardwareTimer::DisableInterrupt() {
|
||||||
m_kernel.System().CoreTiming().UnscheduleEvent(m_event_type,
|
m_kernel.System().CoreTiming().UnscheduleEventWithoutWait(m_event_type,
|
||||||
Core::Timing::UnscheduleEventType::NoWait);
|
reinterpret_cast<uintptr_t>(this));
|
||||||
m_wakeup_time = std::numeric_limits<s64>::max();
|
m_wakeup_time = std::numeric_limits<s64>::max();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,7 +434,7 @@ Result KPageTableBase::InitializeForProcess(Svc::CreateProcessFlag as_type, bool
|
|||||||
void KPageTableBase::Finalize() {
|
void KPageTableBase::Finalize() {
|
||||||
auto HostUnmapCallback = [&](KProcessAddress addr, u64 size) {
|
auto HostUnmapCallback = [&](KProcessAddress addr, u64 size) {
|
||||||
if (Settings::IsFastmemEnabled()) {
|
if (Settings::IsFastmemEnabled()) {
|
||||||
m_system.DeviceMemory().buffer.Unmap(GetInteger(addr), size, false);
|
m_system.DeviceMemory().buffer.Unmap(GetInteger(addr), size);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -5243,7 +5243,7 @@ Result KPageTableBase::MapPhysicalMemory(KProcessAddress address, size_t size) {
|
|||||||
// Unmap.
|
// Unmap.
|
||||||
R_ASSERT(this->Operate(updater.GetPageList(), cur_address,
|
R_ASSERT(this->Operate(updater.GetPageList(), cur_address,
|
||||||
cur_pages, 0, false, unmap_properties,
|
cur_pages, 0, false, unmap_properties,
|
||||||
OperationType::UnmapPhysical, true));
|
OperationType::Unmap, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we're done.
|
// Check if we're done.
|
||||||
@ -5326,7 +5326,7 @@ Result KPageTableBase::MapPhysicalMemory(KProcessAddress address, size_t size) {
|
|||||||
// Map the papges.
|
// Map the papges.
|
||||||
R_TRY(this->Operate(updater.GetPageList(), cur_address, map_pages,
|
R_TRY(this->Operate(updater.GetPageList(), cur_address, map_pages,
|
||||||
cur_pg, map_properties,
|
cur_pg, map_properties,
|
||||||
OperationType::MapFirstGroupPhysical, false));
|
OperationType::MapFirstGroup, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5480,7 +5480,7 @@ Result KPageTableBase::UnmapPhysicalMemory(KProcessAddress address, size_t size)
|
|||||||
|
|
||||||
// Unmap.
|
// Unmap.
|
||||||
R_ASSERT(this->Operate(updater.GetPageList(), cur_address, cur_pages, 0, false,
|
R_ASSERT(this->Operate(updater.GetPageList(), cur_address, cur_pages, 0, false,
|
||||||
unmap_properties, OperationType::UnmapPhysical, false));
|
unmap_properties, OperationType::Unmap, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we're done.
|
// Check if we're done.
|
||||||
@ -5655,10 +5655,7 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
|
|||||||
// or free them to the page list, and so it goes unused (along with page properties).
|
// or free them to the page list, and so it goes unused (along with page properties).
|
||||||
|
|
||||||
switch (operation) {
|
switch (operation) {
|
||||||
case OperationType::Unmap:
|
case OperationType::Unmap: {
|
||||||
case OperationType::UnmapPhysical: {
|
|
||||||
const bool separate_heap = operation == OperationType::UnmapPhysical;
|
|
||||||
|
|
||||||
// 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({ pages_to_close.CloseAndReset(); });
|
SCOPE_EXIT({ pages_to_close.CloseAndReset(); });
|
||||||
@ -5667,7 +5664,7 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
|
|||||||
this->MakePageGroup(pages_to_close, virt_addr, num_pages);
|
this->MakePageGroup(pages_to_close, virt_addr, num_pages);
|
||||||
|
|
||||||
// Unmap.
|
// Unmap.
|
||||||
m_memory->UnmapRegion(*m_impl, virt_addr, num_pages * PageSize, separate_heap);
|
m_memory->UnmapRegion(*m_impl, virt_addr, num_pages * PageSize);
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
@ -5675,7 +5672,7 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
|
|||||||
ASSERT(virt_addr != 0);
|
ASSERT(virt_addr != 0);
|
||||||
ASSERT(Common::IsAligned(GetInteger(virt_addr), PageSize));
|
ASSERT(Common::IsAligned(GetInteger(virt_addr), PageSize));
|
||||||
m_memory->MapMemoryRegion(*m_impl, virt_addr, num_pages * PageSize, phys_addr,
|
m_memory->MapMemoryRegion(*m_impl, virt_addr, num_pages * PageSize, phys_addr,
|
||||||
ConvertToMemoryPermission(properties.perm), false);
|
ConvertToMemoryPermission(properties.perm));
|
||||||
|
|
||||||
// Open references to pages, if we should.
|
// Open references to pages, if we should.
|
||||||
if (this->IsHeapPhysicalAddress(phys_addr)) {
|
if (this->IsHeapPhysicalAddress(phys_addr)) {
|
||||||
@ -5714,19 +5711,16 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
|
|||||||
|
|
||||||
switch (operation) {
|
switch (operation) {
|
||||||
case OperationType::MapGroup:
|
case OperationType::MapGroup:
|
||||||
case OperationType::MapFirstGroup:
|
case OperationType::MapFirstGroup: {
|
||||||
case OperationType::MapFirstGroupPhysical: {
|
|
||||||
const bool separate_heap = operation == OperationType::MapFirstGroupPhysical;
|
|
||||||
|
|
||||||
// We want to maintain a new reference to every page in the group.
|
// We want to maintain a new reference to every page in the group.
|
||||||
KScopedPageGroup spg(page_group, operation == OperationType::MapGroup);
|
KScopedPageGroup spg(page_group, operation != OperationType::MapFirstGroup);
|
||||||
|
|
||||||
for (const auto& node : page_group) {
|
for (const auto& node : page_group) {
|
||||||
const size_t size{node.GetNumPages() * PageSize};
|
const size_t size{node.GetNumPages() * PageSize};
|
||||||
|
|
||||||
// Map the pages.
|
// Map the pages.
|
||||||
m_memory->MapMemoryRegion(*m_impl, virt_addr, size, node.GetAddress(),
|
m_memory->MapMemoryRegion(*m_impl, virt_addr, size, node.GetAddress(),
|
||||||
ConvertToMemoryPermission(properties.perm), separate_heap);
|
ConvertToMemoryPermission(properties.perm));
|
||||||
|
|
||||||
virt_addr += size;
|
virt_addr += size;
|
||||||
}
|
}
|
||||||
|
@ -104,9 +104,6 @@ protected:
|
|||||||
ChangePermissionsAndRefresh = 5,
|
ChangePermissionsAndRefresh = 5,
|
||||||
ChangePermissionsAndRefreshAndFlush = 6,
|
ChangePermissionsAndRefreshAndFlush = 6,
|
||||||
Separate = 7,
|
Separate = 7,
|
||||||
|
|
||||||
MapFirstGroupPhysical = 65000,
|
|
||||||
UnmapPhysical = 65001,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr size_t MaxPhysicalMapAlignment = 1_GiB;
|
static constexpr size_t MaxPhysicalMapAlignment = 1_GiB;
|
||||||
|
@ -306,16 +306,12 @@ Result KProcess::Initialize(const Svc::CreateProcessParameter& params, const KPa
|
|||||||
False(params.flags & Svc::CreateProcessFlag::DisableDeviceAddressSpaceMerge);
|
False(params.flags & Svc::CreateProcessFlag::DisableDeviceAddressSpaceMerge);
|
||||||
R_TRY(m_page_table.Initialize(as_type, enable_aslr, enable_das_merge, !enable_aslr, pool,
|
R_TRY(m_page_table.Initialize(as_type, enable_aslr, enable_das_merge, !enable_aslr, pool,
|
||||||
params.code_address, params.code_num_pages * PageSize,
|
params.code_address, params.code_num_pages * PageSize,
|
||||||
m_system_resource, res_limit, m_memory, 0));
|
m_system_resource, res_limit, this->GetMemory(), 0));
|
||||||
}
|
}
|
||||||
ON_RESULT_FAILURE_2 {
|
ON_RESULT_FAILURE_2 {
|
||||||
m_page_table.Finalize();
|
m_page_table.Finalize();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Ensure our memory is initialized.
|
|
||||||
m_memory.SetCurrentPageTable(*this);
|
|
||||||
m_memory.SetGPUDirtyManagers(m_dirty_memory_managers);
|
|
||||||
|
|
||||||
// Ensure we can insert the code region.
|
// Ensure we can insert the code region.
|
||||||
R_UNLESS(m_page_table.CanContain(params.code_address, params.code_num_pages * PageSize,
|
R_UNLESS(m_page_table.CanContain(params.code_address, params.code_num_pages * PageSize,
|
||||||
KMemoryState::Code),
|
KMemoryState::Code),
|
||||||
@ -403,16 +399,12 @@ Result KProcess::Initialize(const Svc::CreateProcessParameter& params,
|
|||||||
False(params.flags & Svc::CreateProcessFlag::DisableDeviceAddressSpaceMerge);
|
False(params.flags & Svc::CreateProcessFlag::DisableDeviceAddressSpaceMerge);
|
||||||
R_TRY(m_page_table.Initialize(as_type, enable_aslr, enable_das_merge, !enable_aslr, pool,
|
R_TRY(m_page_table.Initialize(as_type, enable_aslr, enable_das_merge, !enable_aslr, pool,
|
||||||
params.code_address, code_size, m_system_resource, res_limit,
|
params.code_address, code_size, m_system_resource, res_limit,
|
||||||
m_memory, aslr_space_start));
|
this->GetMemory(), aslr_space_start));
|
||||||
}
|
}
|
||||||
ON_RESULT_FAILURE_2 {
|
ON_RESULT_FAILURE_2 {
|
||||||
m_page_table.Finalize();
|
m_page_table.Finalize();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Ensure our memory is initialized.
|
|
||||||
m_memory.SetCurrentPageTable(*this);
|
|
||||||
m_memory.SetGPUDirtyManagers(m_dirty_memory_managers);
|
|
||||||
|
|
||||||
// Ensure we can insert the code region.
|
// Ensure we can insert the code region.
|
||||||
R_UNLESS(m_page_table.CanContain(params.code_address, code_size, KMemoryState::Code),
|
R_UNLESS(m_page_table.CanContain(params.code_address, code_size, KMemoryState::Code),
|
||||||
ResultInvalidMemoryRegion);
|
ResultInvalidMemoryRegion);
|
||||||
@ -1102,7 +1094,8 @@ void KProcess::UnpinThread(KThread* thread) {
|
|||||||
|
|
||||||
Result KProcess::GetThreadList(s32* out_num_threads, KProcessAddress out_thread_ids,
|
Result KProcess::GetThreadList(s32* out_num_threads, KProcessAddress out_thread_ids,
|
||||||
s32 max_out_count) {
|
s32 max_out_count) {
|
||||||
auto& memory = this->GetMemory();
|
// TODO: use current memory reference
|
||||||
|
auto& memory = m_kernel.System().ApplicationMemory();
|
||||||
|
|
||||||
// Lock the list.
|
// Lock the list.
|
||||||
KScopedLightLock lk(m_list_lock);
|
KScopedLightLock lk(m_list_lock);
|
||||||
@ -1135,15 +1128,14 @@ void KProcess::Switch(KProcess* cur_process, KProcess* next_process) {}
|
|||||||
KProcess::KProcess(KernelCore& kernel)
|
KProcess::KProcess(KernelCore& kernel)
|
||||||
: KAutoObjectWithSlabHeapAndContainer(kernel), m_page_table{kernel}, m_state_lock{kernel},
|
: KAutoObjectWithSlabHeapAndContainer(kernel), m_page_table{kernel}, m_state_lock{kernel},
|
||||||
m_list_lock{kernel}, m_cond_var{kernel.System()}, m_address_arbiter{kernel.System()},
|
m_list_lock{kernel}, m_cond_var{kernel.System()}, m_address_arbiter{kernel.System()},
|
||||||
m_handle_table{kernel}, m_dirty_memory_managers{},
|
m_handle_table{kernel} {}
|
||||||
m_exclusive_monitor{}, m_memory{kernel.System()} {}
|
|
||||||
KProcess::~KProcess() = default;
|
KProcess::~KProcess() = default;
|
||||||
|
|
||||||
Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size,
|
Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size,
|
||||||
KProcessAddress aslr_space_start, bool is_hbl) {
|
KProcessAddress aslr_space_start, bool is_hbl) {
|
||||||
// Create a resource limit for the process.
|
// Create a resource limit for the process.
|
||||||
const auto pool = static_cast<KMemoryManager::Pool>(metadata.GetPoolPartition());
|
const auto physical_memory_size =
|
||||||
const auto physical_memory_size = m_kernel.MemoryManager().GetSize(pool);
|
m_kernel.MemoryManager().GetSize(Kernel::KMemoryManager::Pool::Application);
|
||||||
auto* res_limit =
|
auto* res_limit =
|
||||||
Kernel::CreateResourceLimitForProcess(m_kernel.System(), physical_memory_size);
|
Kernel::CreateResourceLimitForProcess(m_kernel.System(), physical_memory_size);
|
||||||
|
|
||||||
@ -1154,10 +1146,8 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
|
|||||||
Svc::CreateProcessFlag flag{};
|
Svc::CreateProcessFlag flag{};
|
||||||
u64 code_address{};
|
u64 code_address{};
|
||||||
|
|
||||||
// Determine if we are an application.
|
// We are an application.
|
||||||
if (pool == KMemoryManager::Pool::Application) {
|
flag |= Svc::CreateProcessFlag::IsApplication;
|
||||||
flag |= Svc::CreateProcessFlag::IsApplication;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we are 64-bit, create as such.
|
// If we are 64-bit, create as such.
|
||||||
if (metadata.Is64BitProgram()) {
|
if (metadata.Is64BitProgram()) {
|
||||||
@ -1206,8 +1196,8 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
|
|||||||
std::memcpy(params.name.data(), name.data(), sizeof(params.name));
|
std::memcpy(params.name.data(), name.data(), sizeof(params.name));
|
||||||
|
|
||||||
// Initialize for application process.
|
// Initialize for application process.
|
||||||
R_TRY(this->Initialize(params, metadata.GetKernelCapabilities(), res_limit, pool,
|
R_TRY(this->Initialize(params, metadata.GetKernelCapabilities(), res_limit,
|
||||||
aslr_space_start));
|
KMemoryManager::Pool::Application, aslr_space_start));
|
||||||
|
|
||||||
// Assign remaining properties.
|
// Assign remaining properties.
|
||||||
m_is_hbl = is_hbl;
|
m_is_hbl = is_hbl;
|
||||||
@ -1233,25 +1223,22 @@ void KProcess::LoadModule(CodeSet code_set, KProcessAddress base_addr) {
|
|||||||
ReprotectSegment(code_set.DataSegment(), Svc::MemoryPermission::ReadWrite);
|
ReprotectSegment(code_set.DataSegment(), Svc::MemoryPermission::ReadWrite);
|
||||||
|
|
||||||
#ifdef HAS_NCE
|
#ifdef HAS_NCE
|
||||||
if (this->IsApplication() && Settings::IsNceEnabled()) {
|
if (Settings::IsNceEnabled()) {
|
||||||
auto& buffer = m_kernel.System().DeviceMemory().buffer;
|
auto& buffer = m_kernel.System().DeviceMemory().buffer;
|
||||||
const auto& code = code_set.CodeSegment();
|
const auto& code = code_set.CodeSegment();
|
||||||
const auto& patch = code_set.PatchSegment();
|
const auto& patch = code_set.PatchSegment();
|
||||||
buffer.Protect(GetInteger(base_addr + code.addr), code.size,
|
buffer.Protect(GetInteger(base_addr + code.addr), code.size, true, true, true);
|
||||||
Common::MemoryPermission::Read | Common::MemoryPermission::Execute);
|
buffer.Protect(GetInteger(base_addr + patch.addr), patch.size, true, true, true);
|
||||||
buffer.Protect(GetInteger(base_addr + patch.addr), patch.size,
|
|
||||||
Common::MemoryPermission::Read | Common::MemoryPermission::Execute);
|
|
||||||
ReprotectSegment(code_set.PatchSegment(), Svc::MemoryPermission::None);
|
ReprotectSegment(code_set.PatchSegment(), Svc::MemoryPermission::None);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void KProcess::InitializeInterfaces() {
|
void KProcess::InitializeInterfaces() {
|
||||||
m_exclusive_monitor =
|
this->GetMemory().SetCurrentPageTable(*this);
|
||||||
Core::MakeExclusiveMonitor(this->GetMemory(), Core::Hardware::NUM_CPU_CORES);
|
|
||||||
|
|
||||||
#ifdef HAS_NCE
|
#ifdef HAS_NCE
|
||||||
if (this->IsApplication() && Settings::IsNceEnabled()) {
|
if (this->Is64Bit() && Settings::IsNceEnabled()) {
|
||||||
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
|
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
|
||||||
m_arm_interfaces[i] = std::make_unique<Core::ArmNce>(m_kernel.System(), true, i);
|
m_arm_interfaces[i] = std::make_unique<Core::ArmNce>(m_kernel.System(), true, i);
|
||||||
}
|
}
|
||||||
@ -1261,13 +1248,13 @@ void KProcess::InitializeInterfaces() {
|
|||||||
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
|
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
|
||||||
m_arm_interfaces[i] = std::make_unique<Core::ArmDynarmic64>(
|
m_arm_interfaces[i] = std::make_unique<Core::ArmDynarmic64>(
|
||||||
m_kernel.System(), m_kernel.IsMulticore(), this,
|
m_kernel.System(), m_kernel.IsMulticore(), this,
|
||||||
static_cast<Core::DynarmicExclusiveMonitor&>(*m_exclusive_monitor), i);
|
static_cast<Core::DynarmicExclusiveMonitor&>(m_kernel.GetExclusiveMonitor()), i);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
|
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
|
||||||
m_arm_interfaces[i] = std::make_unique<Core::ArmDynarmic32>(
|
m_arm_interfaces[i] = std::make_unique<Core::ArmDynarmic32>(
|
||||||
m_kernel.System(), m_kernel.IsMulticore(), this,
|
m_kernel.System(), m_kernel.IsMulticore(), this,
|
||||||
static_cast<Core::DynarmicExclusiveMonitor&>(*m_exclusive_monitor), i);
|
static_cast<Core::DynarmicExclusiveMonitor&>(m_kernel.GetExclusiveMonitor()), i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1318,10 +1305,9 @@ bool KProcess::RemoveWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointT
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KProcess::GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback) {
|
Core::Memory::Memory& KProcess::GetMemory() const {
|
||||||
for (auto& manager : m_dirty_memory_managers) {
|
// TODO: per-process memory
|
||||||
manager.Gather(callback);
|
return m_kernel.System().ApplicationMemory();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
#include "core/arm/arm_interface.h"
|
#include "core/arm/arm_interface.h"
|
||||||
#include "core/file_sys/program_metadata.h"
|
#include "core/file_sys/program_metadata.h"
|
||||||
#include "core/gpu_dirty_memory_manager.h"
|
|
||||||
#include "core/hle/kernel/code_set.h"
|
#include "core/hle/kernel/code_set.h"
|
||||||
#include "core/hle/kernel/k_address_arbiter.h"
|
#include "core/hle/kernel/k_address_arbiter.h"
|
||||||
#include "core/hle/kernel/k_capabilities.h"
|
#include "core/hle/kernel/k_capabilities.h"
|
||||||
@ -18,7 +17,6 @@
|
|||||||
#include "core/hle/kernel/k_system_resource.h"
|
#include "core/hle/kernel/k_system_resource.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
#include "core/hle/kernel/k_thread.h"
|
||||||
#include "core/hle/kernel/k_thread_local_page.h"
|
#include "core/hle/kernel/k_thread_local_page.h"
|
||||||
#include "core/memory.h"
|
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
@ -128,9 +126,6 @@ private:
|
|||||||
#ifdef HAS_NCE
|
#ifdef HAS_NCE
|
||||||
std::unordered_map<u64, u64> m_post_handlers{};
|
std::unordered_map<u64, u64> m_post_handlers{};
|
||||||
#endif
|
#endif
|
||||||
std::array<Core::GPUDirtyMemoryManager, Core::Hardware::NUM_CPU_CORES> m_dirty_memory_managers;
|
|
||||||
std::unique_ptr<Core::ExclusiveMonitor> m_exclusive_monitor;
|
|
||||||
Core::Memory::Memory m_memory;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Result StartTermination();
|
Result StartTermination();
|
||||||
@ -507,15 +502,7 @@ public:
|
|||||||
|
|
||||||
void InitializeInterfaces();
|
void InitializeInterfaces();
|
||||||
|
|
||||||
Core::Memory::Memory& GetMemory() {
|
Core::Memory::Memory& GetMemory() const;
|
||||||
return m_memory;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback);
|
|
||||||
|
|
||||||
Core::ExclusiveMonitor& GetExclusiveMonitor() const {
|
|
||||||
return *m_exclusive_monitor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Overridden parent functions.
|
// Overridden parent functions.
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -49,21 +49,14 @@ public:
|
|||||||
bool IsSignaled() const override;
|
bool IsSignaled() const override;
|
||||||
void OnClientClosed();
|
void OnClientClosed();
|
||||||
|
|
||||||
|
/// TODO: flesh these out to match the real kernel
|
||||||
Result OnRequest(KSessionRequest* request);
|
Result OnRequest(KSessionRequest* request);
|
||||||
Result SendReply(uintptr_t server_message, uintptr_t server_buffer_size,
|
Result SendReply(bool is_hle = false);
|
||||||
KPhysicalAddress server_message_paddr, bool is_hle = false);
|
Result ReceiveRequest(std::shared_ptr<Service::HLERequestContext>* out_context = nullptr,
|
||||||
Result ReceiveRequest(uintptr_t server_message, uintptr_t server_buffer_size,
|
|
||||||
KPhysicalAddress server_message_paddr,
|
|
||||||
std::shared_ptr<Service::HLERequestContext>* out_context = nullptr,
|
|
||||||
std::weak_ptr<Service::SessionRequestManager> manager = {});
|
std::weak_ptr<Service::SessionRequestManager> manager = {});
|
||||||
|
|
||||||
Result SendReplyHLE() {
|
Result SendReplyHLE() {
|
||||||
R_RETURN(this->SendReply(0, 0, 0, true));
|
return SendReply(true);
|
||||||
}
|
|
||||||
|
|
||||||
Result ReceiveRequestHLE(std::shared_ptr<Service::HLERequestContext>* out_context,
|
|
||||||
std::weak_ptr<Service::SessionRequestManager> manager) {
|
|
||||||
R_RETURN(this->ReceiveRequest(0, 0, 0, out_context, manager));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -33,7 +33,8 @@ void KSession::Initialize(KClientPort* client_port, uintptr_t name) {
|
|||||||
m_name = name;
|
m_name = name;
|
||||||
|
|
||||||
// Set our owner process.
|
// Set our owner process.
|
||||||
m_process = GetCurrentProcessPointer(m_kernel);
|
//! FIXME: this is the wrong process!
|
||||||
|
m_process = m_kernel.ApplicationProcess();
|
||||||
m_process->Open();
|
m_process->Open();
|
||||||
|
|
||||||
// Set our port.
|
// Set our port.
|
||||||
|
@ -1422,7 +1422,8 @@ s32 GetCurrentCoreId(KernelCore& kernel) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Core::Memory::Memory& GetCurrentMemory(KernelCore& kernel) {
|
Core::Memory::Memory& GetCurrentMemory(KernelCore& kernel) {
|
||||||
return GetCurrentProcess(kernel).GetMemory();
|
// TODO: per-process memory
|
||||||
|
return kernel.System().ApplicationMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
KScopedDisableDispatch::~KScopedDisableDispatch() {
|
KScopedDisableDispatch::~KScopedDisableDispatch() {
|
||||||
|
@ -314,7 +314,11 @@ public:
|
|||||||
m_current_core_id = core;
|
m_current_core_id = core;
|
||||||
}
|
}
|
||||||
|
|
||||||
KProcess* GetOwnerProcess() const {
|
KProcess* GetOwnerProcess() {
|
||||||
|
return m_parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
const KProcess* GetOwnerProcess() const {
|
||||||
return m_parent;
|
return m_parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
#include "core/hle/kernel/k_light_lock.h"
|
|
||||||
#include "core/hle/kernel/k_page_group.h"
|
#include "core/hle/kernel/k_page_group.h"
|
||||||
#include "core/hle/kernel/slab_helpers.h"
|
#include "core/hle/kernel/slab_helpers.h"
|
||||||
#include "core/hle/kernel/svc_types.h"
|
#include "core/hle/kernel/svc_types.h"
|
||||||
|
@ -68,6 +68,8 @@ struct KernelCore::Impl {
|
|||||||
|
|
||||||
global_object_list_container = std::make_unique<KAutoObjectWithListContainer>(kernel);
|
global_object_list_container = std::make_unique<KAutoObjectWithListContainer>(kernel);
|
||||||
global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
|
global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
|
||||||
|
global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel);
|
||||||
|
global_handle_table->Initialize(KHandleTable::MaxTableSize);
|
||||||
|
|
||||||
is_phantom_mode_for_singlecore = false;
|
is_phantom_mode_for_singlecore = false;
|
||||||
|
|
||||||
@ -119,8 +121,13 @@ struct KernelCore::Impl {
|
|||||||
next_user_process_id = KProcess::ProcessIdMin;
|
next_user_process_id = KProcess::ProcessIdMin;
|
||||||
next_thread_id = 1;
|
next_thread_id = 1;
|
||||||
|
|
||||||
|
global_handle_table->Finalize();
|
||||||
|
global_handle_table.reset();
|
||||||
|
|
||||||
preemption_event = nullptr;
|
preemption_event = nullptr;
|
||||||
|
|
||||||
|
exclusive_monitor.reset();
|
||||||
|
|
||||||
// Cleanup persistent kernel objects
|
// Cleanup persistent kernel objects
|
||||||
auto CleanupObject = [](KAutoObject* obj) {
|
auto CleanupObject = [](KAutoObject* obj) {
|
||||||
if (obj) {
|
if (obj) {
|
||||||
@ -184,6 +191,8 @@ struct KernelCore::Impl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void InitializePhysicalCores() {
|
void InitializePhysicalCores() {
|
||||||
|
exclusive_monitor =
|
||||||
|
Core::MakeExclusiveMonitor(system.ApplicationMemory(), Core::Hardware::NUM_CPU_CORES);
|
||||||
for (u32 i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
|
for (u32 i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
|
||||||
const s32 core{static_cast<s32>(i)};
|
const s32 core{static_cast<s32>(i)};
|
||||||
|
|
||||||
@ -238,7 +247,7 @@ struct KernelCore::Impl {
|
|||||||
void InitializePreemption(KernelCore& kernel) {
|
void InitializePreemption(KernelCore& kernel) {
|
||||||
preemption_event = Core::Timing::CreateEvent(
|
preemption_event = Core::Timing::CreateEvent(
|
||||||
"PreemptionCallback",
|
"PreemptionCallback",
|
||||||
[this, &kernel](s64 time,
|
[this, &kernel](std::uintptr_t, s64 time,
|
||||||
std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> {
|
std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> {
|
||||||
{
|
{
|
||||||
KScopedSchedulerLock lock(kernel);
|
KScopedSchedulerLock lock(kernel);
|
||||||
@ -782,6 +791,10 @@ struct KernelCore::Impl {
|
|||||||
|
|
||||||
std::shared_ptr<Core::Timing::EventType> preemption_event;
|
std::shared_ptr<Core::Timing::EventType> preemption_event;
|
||||||
|
|
||||||
|
// This is the kernel's handle table or supervisor handle table which
|
||||||
|
// stores all the objects in place.
|
||||||
|
std::unique_ptr<KHandleTable> global_handle_table;
|
||||||
|
|
||||||
std::unique_ptr<KAutoObjectWithListContainer> global_object_list_container;
|
std::unique_ptr<KAutoObjectWithListContainer> global_object_list_container;
|
||||||
|
|
||||||
std::unique_ptr<KObjectNameGlobalData> object_name_global_data;
|
std::unique_ptr<KObjectNameGlobalData> object_name_global_data;
|
||||||
@ -792,6 +805,7 @@ struct KernelCore::Impl {
|
|||||||
std::mutex server_lock;
|
std::mutex server_lock;
|
||||||
std::vector<std::unique_ptr<Service::ServerManager>> server_managers;
|
std::vector<std::unique_ptr<Service::ServerManager>> server_managers;
|
||||||
|
|
||||||
|
std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
|
||||||
std::array<std::unique_ptr<Kernel::PhysicalCore>, Core::Hardware::NUM_CPU_CORES> cores;
|
std::array<std::unique_ptr<Kernel::PhysicalCore>, Core::Hardware::NUM_CPU_CORES> cores;
|
||||||
|
|
||||||
// Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others
|
// Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others
|
||||||
@ -868,6 +882,10 @@ KResourceLimit* KernelCore::GetSystemResourceLimit() {
|
|||||||
return impl->system_resource_limit;
|
return impl->system_resource_limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KScopedAutoObject<KThread> KernelCore::RetrieveThreadFromGlobalHandleTable(Handle handle) const {
|
||||||
|
return impl->global_handle_table->GetObject<KThread>(handle);
|
||||||
|
}
|
||||||
|
|
||||||
void KernelCore::AppendNewProcess(KProcess* process) {
|
void KernelCore::AppendNewProcess(KProcess* process) {
|
||||||
impl->process_list.push_back(process);
|
impl->process_list.push_back(process);
|
||||||
}
|
}
|
||||||
@ -941,6 +959,14 @@ Kernel::KHardwareTimer& KernelCore::HardwareTimer() {
|
|||||||
return *impl->hardware_timer;
|
return *impl->hardware_timer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() {
|
||||||
|
return *impl->exclusive_monitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() const {
|
||||||
|
return *impl->exclusive_monitor;
|
||||||
|
}
|
||||||
|
|
||||||
KAutoObjectWithListContainer& KernelCore::ObjectListContainer() {
|
KAutoObjectWithListContainer& KernelCore::ObjectListContainer() {
|
||||||
return *impl->global_object_list_container;
|
return *impl->global_object_list_container;
|
||||||
}
|
}
|
||||||
@ -1004,6 +1030,14 @@ u64 KernelCore::CreateNewUserProcessID() {
|
|||||||
return impl->next_user_process_id++;
|
return impl->next_user_process_id++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KHandleTable& KernelCore::GlobalHandleTable() {
|
||||||
|
return *impl->global_handle_table;
|
||||||
|
}
|
||||||
|
|
||||||
|
const KHandleTable& KernelCore::GlobalHandleTable() const {
|
||||||
|
return *impl->global_handle_table;
|
||||||
|
}
|
||||||
|
|
||||||
void KernelCore::RegisterCoreThread(std::size_t core_id) {
|
void KernelCore::RegisterCoreThread(std::size_t core_id) {
|
||||||
impl->RegisterCoreThread(core_id);
|
impl->RegisterCoreThread(core_id);
|
||||||
}
|
}
|
||||||
|
@ -116,6 +116,9 @@ public:
|
|||||||
/// Retrieves a shared pointer to the system resource limit instance.
|
/// Retrieves a shared pointer to the system resource limit instance.
|
||||||
KResourceLimit* GetSystemResourceLimit();
|
KResourceLimit* GetSystemResourceLimit();
|
||||||
|
|
||||||
|
/// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table.
|
||||||
|
KScopedAutoObject<KThread> RetrieveThreadFromGlobalHandleTable(Handle handle) const;
|
||||||
|
|
||||||
/// Adds the given shared pointer to an internal list of active processes.
|
/// Adds the given shared pointer to an internal list of active processes.
|
||||||
void AppendNewProcess(KProcess* process);
|
void AppendNewProcess(KProcess* process);
|
||||||
|
|
||||||
@ -167,6 +170,10 @@ public:
|
|||||||
/// Stops execution of 'id' core, in order to reschedule a new thread.
|
/// Stops execution of 'id' core, in order to reschedule a new thread.
|
||||||
void PrepareReschedule(std::size_t id);
|
void PrepareReschedule(std::size_t id);
|
||||||
|
|
||||||
|
Core::ExclusiveMonitor& GetExclusiveMonitor();
|
||||||
|
|
||||||
|
const Core::ExclusiveMonitor& GetExclusiveMonitor() const;
|
||||||
|
|
||||||
KAutoObjectWithListContainer& ObjectListContainer();
|
KAutoObjectWithListContainer& ObjectListContainer();
|
||||||
|
|
||||||
const KAutoObjectWithListContainer& ObjectListContainer() const;
|
const KAutoObjectWithListContainer& ObjectListContainer() const;
|
||||||
|
@ -18,13 +18,13 @@ public:
|
|||||||
static constexpr inline u64 NullTag = 0;
|
static constexpr inline u64 NullTag = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum ReceiveListCountType : u32 {
|
enum class ReceiveListCountType : u32 {
|
||||||
ReceiveListCountType_None = 0,
|
None = 0,
|
||||||
ReceiveListCountType_ToMessageBuffer = 1,
|
ToMessageBuffer = 1,
|
||||||
ReceiveListCountType_ToSingleBuffer = 2,
|
ToSingleBuffer = 2,
|
||||||
|
|
||||||
ReceiveListCountType_CountOffset = 2,
|
CountOffset = 2,
|
||||||
ReceiveListCountType_CountMax = 13,
|
CountMax = 13,
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -591,16 +591,16 @@ public:
|
|||||||
// Add the size of the receive list.
|
// Add the size of the receive list.
|
||||||
const auto count = hdr.GetReceiveListCount();
|
const auto count = hdr.GetReceiveListCount();
|
||||||
switch (count) {
|
switch (count) {
|
||||||
case MessageHeader::ReceiveListCountType_None:
|
case MessageHeader::ReceiveListCountType::None:
|
||||||
break;
|
break;
|
||||||
case MessageHeader::ReceiveListCountType_ToMessageBuffer:
|
case MessageHeader::ReceiveListCountType::ToMessageBuffer:
|
||||||
break;
|
break;
|
||||||
case MessageHeader::ReceiveListCountType_ToSingleBuffer:
|
case MessageHeader::ReceiveListCountType::ToSingleBuffer:
|
||||||
msg_size += ReceiveListEntry::GetDataSize();
|
msg_size += ReceiveListEntry::GetDataSize();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
msg_size += (static_cast<s32>(count) -
|
msg_size += (static_cast<s32>(count) -
|
||||||
static_cast<s32>(MessageHeader::ReceiveListCountType_CountOffset)) *
|
static_cast<s32>(MessageHeader::ReceiveListCountType::CountOffset)) *
|
||||||
ReceiveListEntry::GetDataSize();
|
ReceiveListEntry::GetDataSize();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -118,6 +118,7 @@ Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
|
|
||||||
case InfoType::IsApplication:
|
case InfoType::IsApplication:
|
||||||
|
LOG_WARNING(Kernel_SVC, "(STUBBED) Assuming process is application");
|
||||||
*result = process->IsApplication();
|
*result = process->IsApplication();
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
|
|
||||||
|
@ -48,7 +48,8 @@ Result ReplyAndReceiveImpl(KernelCore& kernel, int32_t* out_index, uintptr_t mes
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Send the reply.
|
// Send the reply.
|
||||||
R_TRY(session->SendReply(message, buffer_size, message_paddr));
|
R_TRY(session->SendReply());
|
||||||
|
// R_TRY(session->SendReply(message, buffer_size, message_paddr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Receive a message.
|
// Receive a message.
|
||||||
@ -84,7 +85,8 @@ Result ReplyAndReceiveImpl(KernelCore& kernel, int32_t* out_index, uintptr_t mes
|
|||||||
if (R_SUCCEEDED(result)) {
|
if (R_SUCCEEDED(result)) {
|
||||||
KServerSession* session = objs[index]->DynamicCast<KServerSession*>();
|
KServerSession* session = objs[index]->DynamicCast<KServerSession*>();
|
||||||
if (session != nullptr) {
|
if (session != nullptr) {
|
||||||
result = session->ReceiveRequest(message, buffer_size, message_paddr);
|
// result = session->ReceiveRequest(message, buffer_size, message_paddr);
|
||||||
|
result = session->ReceiveRequest();
|
||||||
if (ResultNotFound == result) {
|
if (ResultNotFound == result) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -38,9 +38,7 @@ constexpr Result ResultInvalidState{ErrorModule::Kernel, 125};
|
|||||||
constexpr Result ResultReservedUsed{ErrorModule::Kernel, 126};
|
constexpr Result ResultReservedUsed{ErrorModule::Kernel, 126};
|
||||||
constexpr Result ResultPortClosed{ErrorModule::Kernel, 131};
|
constexpr Result ResultPortClosed{ErrorModule::Kernel, 131};
|
||||||
constexpr Result ResultLimitReached{ErrorModule::Kernel, 132};
|
constexpr Result ResultLimitReached{ErrorModule::Kernel, 132};
|
||||||
constexpr Result ResultReceiveListBroken{ErrorModule::Kernel, 258};
|
|
||||||
constexpr Result ResultOutOfAddressSpace{ErrorModule::Kernel, 259};
|
constexpr Result ResultOutOfAddressSpace{ErrorModule::Kernel, 259};
|
||||||
constexpr Result ResultMessageTooLarge{ErrorModule::Kernel, 260};
|
|
||||||
constexpr Result ResultInvalidId{ErrorModule::Kernel, 519};
|
constexpr Result ResultInvalidId{ErrorModule::Kernel, 519};
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
@ -1513,7 +1513,8 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle);
|
auto transfer_mem =
|
||||||
|
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle);
|
||||||
|
|
||||||
if (transfer_mem.IsNull()) {
|
if (transfer_mem.IsNull()) {
|
||||||
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
|
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
|
||||||
@ -1523,7 +1524,8 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u8> memory(transfer_mem->GetSize());
|
std::vector<u8> memory(transfer_mem->GetSize());
|
||||||
ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size());
|
system.ApplicationMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(),
|
||||||
|
memory.size());
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
@ -1545,7 +1547,8 @@ void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle);
|
auto transfer_mem =
|
||||||
|
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle);
|
||||||
|
|
||||||
if (transfer_mem.IsNull()) {
|
if (transfer_mem.IsNull()) {
|
||||||
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
|
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
|
||||||
@ -1555,7 +1558,8 @@ void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u8> memory(transfer_mem->GetSize());
|
std::vector<u8> memory(transfer_mem->GetSize());
|
||||||
ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size());
|
system.ApplicationMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(),
|
||||||
|
memory.size());
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
|
@ -454,8 +454,10 @@ void AudRenU::OpenAudioRenderer(HLERequestContext& ctx) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle)};
|
const auto& handle_table{system.ApplicationProcess()->GetHandleTable()};
|
||||||
auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
|
auto process{handle_table.GetObject<Kernel::KProcess>(process_handle)};
|
||||||
|
auto transfer_memory{
|
||||||
|
process->GetHandleTable().GetObject<Kernel::KTransferMemory>(transfer_memory_handle)};
|
||||||
|
|
||||||
const auto session_id{impl->GetSessionId()};
|
const auto session_id{impl->GetSessionId()};
|
||||||
if (session_id == -1) {
|
if (session_id == -1) {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user