From 6efc13a6670769ccccc2b302c8dd457e25e97c82 Mon Sep 17 00:00:00 2001 From: Filippo Scognamiglio Date: Mon, 29 Jul 2024 23:20:25 +0200 Subject: [PATCH] Add CUT3 and allow changing HD mode quality via settings. --- buildSrc/src/main/java/deps.kt | 2 +- .../feature/settings/SettingsManager.kt | 13 +- .../advanced/AdvancedSettingsScreen.kt | 12 +- .../settings/general/SettingsScreen.kt | 15 ++ .../app/shared/game/BaseGameActivity.kt | 9 +- .../lemuroid/app/shared/game/ShaderChooser.kt | 168 +++++++++++++----- .../app/shared/settings/HDModeQuality.kt | 14 ++ .../app/utils/android/settings/Components.kt | 26 ++- .../app/utils/android/settings/States.kt | 11 ++ .../SafeIntPreferenceSettingValueState.kt | 46 +++++ .../utils/settings/SharedPreferenceUtils.kt | 8 + lemuroid-app/src/main/res/values/keys.xml | 2 +- lemuroid-app/src/main/res/values/strings.xml | 6 +- .../src/main/res/xml/mobile_settings.xml | 116 ------------ .../main/res/xml/mobile_settings_advanced.xml | 72 -------- lemuroid-app/src/main/res/xml/tv_settings.xml | 19 +- 16 files changed, 276 insertions(+), 263 deletions(-) create mode 100644 lemuroid-app/src/main/java/com/swordfish/lemuroid/app/shared/settings/HDModeQuality.kt create mode 100644 lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/settings/SafeIntPreferenceSettingValueState.kt delete mode 100644 lemuroid-app/src/main/res/xml/mobile_settings.xml delete mode 100644 lemuroid-app/src/main/res/xml/mobile_settings_advanced.xml diff --git a/buildSrc/src/main/java/deps.kt b/buildSrc/src/main/java/deps.kt index 9d3e0dfb9f..1c167b30d4 100644 --- a/buildSrc/src/main/java/deps.kt +++ b/buildSrc/src/main/java/deps.kt @@ -23,7 +23,7 @@ object deps { const val serialization = "1.2.2" const val fragment = "1.5.1" const val activity = "1.7.2" - const val libretrodroid = "0.11.1" + const val libretrodroid = "c36b44fbd7" const val radialgamepad = "2.0.0" const val composeBom = "2024.02.02" diff --git a/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/mobile/feature/settings/SettingsManager.kt b/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/mobile/feature/settings/SettingsManager.kt index f136514a69..4373537bb5 100644 --- a/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/mobile/feature/settings/SettingsManager.kt +++ b/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/mobile/feature/settings/SettingsManager.kt @@ -4,6 +4,7 @@ import android.content.Context import android.content.SharedPreferences import com.fredporciuncula.flow.preferences.FlowSharedPreferences import com.swordfish.lemuroid.R +import com.swordfish.lemuroid.app.shared.settings.HDModeQuality import com.swordfish.lemuroid.common.math.Fraction import com.swordfish.lemuroid.lib.storage.cache.CacheCleaner import dagger.Lazy @@ -31,7 +32,7 @@ class SettingsManager(private val context: Context, sharedPreferences: Lazy= 3 && hdMode && !forceLegacyHdMode + Timber.i("Choosing shader for this config: screenFilter= $screenFilter hdMode=$hdMode hdModeQuality=$requestedHdModeQuality") + val hdModeQuality = if (context.getGLSLVersion() >= 3) { + requestedHdModeQuality + } else { + HDModeQuality.LOW + } return when { - useNewHdMode -> getHDShaderForSystem(system) - hdMode -> getLegacyHDShaderForSystem(system) + hdMode -> getHDShaderForSystem(system, hdModeQuality) else -> when (screenFilter) { "crt" -> ShaderConfig.CRT @@ -59,7 +65,15 @@ object ShaderChooser { } } - private fun getLegacyHDShaderForSystem(system: GameSystem): ShaderConfig.CUT { + private fun getHDShaderForSystem(system: GameSystem, hdModeQuality: HDModeQuality): ShaderConfig { + return when (hdModeQuality) { + HDModeQuality.LOW -> getLowQualityHdMode(system) + HDModeQuality.MEDIUM -> getMediumQualityHdMode(system) + HDModeQuality.HIGH -> getHighQualityHdMode(system) + } + } + + private fun getLowQualityHdMode(system: GameSystem): ShaderConfig { val upscale8BitsMobile = ShaderConfig.CUT( blendMinContrastEdge = 0.00f, @@ -102,78 +116,146 @@ object ShaderChooser { blendMaxSharpness = 0.50f, ) - return when (system.id) { - SystemID.GBA -> upscale16BitsMobile - SystemID.GBC -> upscale8BitsMobile - SystemID.GB -> upscale8BitsMobile - SystemID.N64 -> upscale32Bits - SystemID.GENESIS -> upscale16Bits - SystemID.SEGACD -> upscale16Bits - SystemID.NES -> upscale8Bits - SystemID.SNES -> upscale16Bits - SystemID.FBNEO -> upscale32Bits - SystemID.SMS -> upscale8Bits - SystemID.PSP -> modern - SystemID.NDS -> upscale32Bits - SystemID.GG -> upscale8BitsMobile - SystemID.ATARI2600 -> upscale8Bits - SystemID.PSX -> upscale32Bits - SystemID.MAME2003PLUS -> upscale32Bits - SystemID.ATARI7800 -> upscale8Bits - SystemID.PC_ENGINE -> upscale16Bits - SystemID.LYNX -> upscale8BitsMobile - SystemID.DOS -> upscale32Bits - SystemID.NGP -> upscale8BitsMobile - SystemID.NGC -> upscale8BitsMobile - SystemID.WS -> upscale16BitsMobile - SystemID.WSC -> upscale16BitsMobile - SystemID.NINTENDO_3DS -> modern - } + return getConfigForSystem( + system, + upscale16BitsMobile, + upscale8BitsMobile, + upscale32Bits, + upscale16Bits, + upscale8Bits, + modern + ) } - private fun getHDShaderForSystem(system: GameSystem): ShaderConfig.CUT2 { + private fun getMediumQualityHdMode(system: GameSystem): ShaderConfig { val upscale8BitsMobile = ShaderConfig.CUT2( blendMinContrastEdge = 0.00f, - blendMaxContrastEdge = 0.50f, - blendMaxSharpness = 0.85f, + blendMaxContrastEdge = 0.30f, + softEdgesSharpeningAmount = 0.75f, + blendMaxSharpness = 0.75f, ) val upscale8Bits = ShaderConfig.CUT2( blendMinContrastEdge = 0.00f, - blendMaxContrastEdge = 0.50f, + blendMaxContrastEdge = 0.30f, + softEdgesSharpeningAmount = 0.75f, blendMaxSharpness = 0.75f, ) val upscale16BitsMobile = ShaderConfig.CUT2( blendMinContrastEdge = 0.10f, - blendMaxContrastEdge = 0.60f, - blendMaxSharpness = 0.85f, + blendMaxContrastEdge = 0.40f, + softEdgesSharpeningAmount = 0.75f, + blendMaxSharpness = 0.75f, ) val upscale16Bits = ShaderConfig.CUT2( blendMinContrastEdge = 0.10f, - blendMaxContrastEdge = 0.60f, + blendMaxContrastEdge = 0.40f, + softEdgesSharpeningAmount = 0.75f, blendMaxSharpness = 0.75f, ) val upscale32Bits = ShaderConfig.CUT2( - blendMinContrastEdge = 0.25f, - blendMaxContrastEdge = 0.75f, + blendMinContrastEdge = 0.10f, + blendMaxContrastEdge = 0.40f, + softEdgesSharpeningAmount = 0.75f, blendMaxSharpness = 0.75f, ) val modern = ShaderConfig.CUT2( - blendMinContrastEdge = 0.25f, - blendMaxContrastEdge = 0.75f, + blendMinContrastEdge = 0.10f, + blendMaxContrastEdge = 0.40f, + softEdgesSharpeningAmount = 0.75f, + blendMaxSharpness = 0.50f, + ) + + return getConfigForSystem( + system, + upscale16BitsMobile, + upscale8BitsMobile, + upscale32Bits, + upscale16Bits, + upscale8Bits, + modern + ) + } + + private fun getHighQualityHdMode(system: GameSystem): ShaderConfig { + val upscale8BitsMobile = + ShaderConfig.CUT3( + blendMinContrastEdge = 0.00f, + blendMaxContrastEdge = 0.30f, + softEdgesSharpeningAmount = 0.75f, + blendMaxSharpness = 0.75f, + ) + + val upscale8Bits = + ShaderConfig.CUT3( + blendMinContrastEdge = 0.00f, + blendMaxContrastEdge = 0.30f, + softEdgesSharpeningAmount = 0.75f, + blendMaxSharpness = 0.75f, + ) + + val upscale16BitsMobile = + ShaderConfig.CUT3( + blendMinContrastEdge = 0.10f, + blendMaxContrastEdge = 0.40f, + softEdgesSharpeningAmount = 0.75f, + blendMaxSharpness = 0.75f, + ) + + val upscale16Bits = + ShaderConfig.CUT3( + blendMinContrastEdge = 0.10f, + blendMaxContrastEdge = 0.40f, + softEdgesSharpeningAmount = 0.75f, + blendMaxSharpness = 0.75f, + ) + + val upscale32Bits = + ShaderConfig.CUT3( + blendMinContrastEdge = 0.10f, + blendMaxContrastEdge = 0.40f, + softEdgesSharpeningAmount = 0.75f, + blendMaxSharpness = 0.75f, + ) + + val modern = + ShaderConfig.CUT3( + blendMinContrastEdge = 0.10f, + blendMaxContrastEdge = 0.40f, + softEdgesSharpeningAmount = 0.75f, blendMaxSharpness = 0.50f, ) + return getConfigForSystem( + system, + upscale16BitsMobile, + upscale8BitsMobile, + upscale32Bits, + upscale16Bits, + upscale8Bits, + modern + ) + } + + private fun getConfigForSystem( + system: GameSystem, + upscale16BitsMobile: ShaderConfig, + upscale8BitsMobile: ShaderConfig, + upscale32Bits: ShaderConfig, + upscale16Bits: ShaderConfig, + upscale8Bits: ShaderConfig, + modern: ShaderConfig + ): ShaderConfig { return when (system.id) { SystemID.GBA -> upscale16BitsMobile SystemID.GBC -> upscale8BitsMobile diff --git a/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/shared/settings/HDModeQuality.kt b/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/shared/settings/HDModeQuality.kt new file mode 100644 index 0000000000..cacfad9184 --- /dev/null +++ b/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/shared/settings/HDModeQuality.kt @@ -0,0 +1,14 @@ +package com.swordfish.lemuroid.app.shared.settings + +enum class HDModeQuality { + LOW, + MEDIUM, + HIGH; + + companion object { + fun parse(value: Int): HDModeQuality { + val result = kotlin.runCatching { HDModeQuality.values()[value] } + return result.getOrNull() ?: MEDIUM + } + } +} diff --git a/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/android/settings/Components.kt b/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/android/settings/Components.kt index add7e7c4e0..9f7f2d2f5e 100644 --- a/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/android/settings/Components.kt +++ b/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/android/settings/Components.kt @@ -32,10 +32,10 @@ fun LemuroidSettingsPage( ) { Column( modifier = - modifier - .fillMaxWidth() - .verticalScroll(rememberScrollState()) - .padding(top = 16.dp, bottom = 16.dp), + modifier + .fillMaxWidth() + .verticalScroll(rememberScrollState()) + .padding(top = 16.dp, bottom = 16.dp), verticalArrangement = Arrangement.spacedBy(16.dp), ) { content() @@ -112,9 +112,9 @@ fun LemuroidCardSettingsGroup( Surface { Column( modifier = - modifier - .fillMaxWidth() - .padding(start = 16.dp, end = 16.dp), + modifier + .fillMaxWidth() + .padding(start = 16.dp, end = 16.dp), ) { OutlinedCard { if (title != null) { @@ -131,9 +131,18 @@ fun LemuroidSettingsSlider( modifier: Modifier = Modifier, state: SettingValueState, steps: Int, + enabled: Boolean, valueRange: ClosedFloatingPointRange, title: @Composable () -> Unit, + subtitle: @Composable () -> Unit = { }, ) { + val defaultColors = ListItemDefaults.colors() + val disabledColors = ListItemDefaults.colors( + headlineColor = defaultColors.disabledHeadlineColor, + leadingIconColor = defaultColors.disabledLeadingIconColor, + trailingIconColor = defaultColors.disabledTrailingIconColor, + ) + SettingsSlider( modifier = modifier, steps = steps, @@ -141,6 +150,9 @@ fun LemuroidSettingsSlider( onValueChange = { state.value = it.roundToInt() }, valueRange = valueRange, title = title, + subtitle = subtitle, + enabled = enabled, + colors = if (enabled) defaultColors else disabledColors ) } diff --git a/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/android/settings/States.kt b/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/android/settings/States.kt index 6146805228..7908aff4dc 100644 --- a/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/android/settings/States.kt +++ b/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/android/settings/States.kt @@ -5,6 +5,7 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import com.swordfish.lemuroid.app.utils.settings.rememberSafePreferenceBooleanSettingState import com.swordfish.lemuroid.app.utils.settings.rememberSafePreferenceIndexSettingState +import com.swordfish.lemuroid.app.utils.settings.rememberSafePreferenceIntSettingState import com.swordfish.lemuroid.app.utils.settings.rememberSafePreferenceStringsSetSettingState import com.swordfish.lemuroid.lib.preferences.SharedPreferencesHelper @@ -52,3 +53,13 @@ fun stringsSetPreferenceState( defaultValue = default, preferences = SharedPreferencesHelper.getSharedPreferences(LocalContext.current), ) + +@Composable +fun intPreferenceState( + key: String, + default: Int, +) = rememberSafePreferenceIntSettingState( + key = key, + defaultValue = default, + preferences = SharedPreferencesHelper.getSharedPreferences(LocalContext.current), +) diff --git a/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/settings/SafeIntPreferenceSettingValueState.kt b/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/settings/SafeIntPreferenceSettingValueState.kt new file mode 100644 index 0000000000..ab71dced4c --- /dev/null +++ b/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/settings/SafeIntPreferenceSettingValueState.kt @@ -0,0 +1,46 @@ +package com.swordfish.lemuroid.app.utils.settings + +import android.content.SharedPreferences +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.platform.LocalContext +import androidx.core.content.edit +import androidx.preference.PreferenceManager +import com.alorma.compose.settings.storage.base.SettingValueState + +@Composable +fun rememberSafePreferenceIntSettingState( + key: String, + defaultValue: Int, + preferences: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(LocalContext.current), +): SafeIntPreferenceSettingValueState { + return remember { + SafeIntPreferenceSettingValueState( + preferences = preferences, + key = key, + defaultValue = defaultValue, + ) + } +} + +class SafeIntPreferenceSettingValueState( + private val preferences: SharedPreferences, + val key: String, + val defaultValue: Int = 0, +) : SettingValueState { + private var _value by mutableStateOf(preferences.safeGetInt(key, defaultValue)) + + override var value: Int + set(value) { + _value = value + preferences.edit { putInt(key, value) } + } + get() = _value + + override fun reset() { + value = defaultValue + } +} diff --git a/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/settings/SharedPreferenceUtils.kt b/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/settings/SharedPreferenceUtils.kt index 2793978445..29933b660a 100644 --- a/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/settings/SharedPreferenceUtils.kt +++ b/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/settings/SharedPreferenceUtils.kt @@ -2,6 +2,14 @@ package com.swordfish.lemuroid.app.utils.settings import android.content.SharedPreferences +fun SharedPreferences.safeGetInt( + key: String, + defValue: Int, +): Int { + val result = runCatching { getInt(key, defValue) } + return result.getOrDefault(defValue) +} + fun SharedPreferences.safeGetString( key: String, defValue: String?, diff --git a/lemuroid-app/src/main/res/values/keys.xml b/lemuroid-app/src/main/res/values/keys.xml index a6e260fe41..ca00c4a6a5 100644 --- a/lemuroid-app/src/main/res/values/keys.xml +++ b/lemuroid-app/src/main/res/values/keys.xml @@ -11,6 +11,7 @@ reset_gamepad_bindings haptic_feedback_mode tilt_sensitivity_index + hd_mode_quality autosave reset_settings low_latency_audio @@ -26,7 +27,6 @@ shader_filter_0 hd_mode - legacy_hd_mode none diff --git a/lemuroid-app/src/main/res/values/strings.xml b/lemuroid-app/src/main/res/values/strings.xml index 7fad987611..f25946d3aa 100644 --- a/lemuroid-app/src/main/res/values/strings.xml +++ b/lemuroid-app/src/main/res/values/strings.xml @@ -27,12 +27,15 @@ Input Miscellaneous Autosave state + Save state when exiting via game menu Vibrate on touch Tilt sensor sensitivity + HD mode quality Cache size limit HD mode Apply post-processing upscaling filter + Adjust the quality of HD mode External devices Configure external gamepads and keyboards @@ -60,9 +63,6 @@ Prefer low-latency audio Reduce audio latency on supported devices. Might increase audio glitches. - Prefer legacy HD mode - Always use legacy HD mode. Trades some quality for performances. - Direct game load (Experimental) Reduce loading time and cache usage on supported consoles. diff --git a/lemuroid-app/src/main/res/xml/mobile_settings.xml b/lemuroid-app/src/main/res/xml/mobile_settings.xml deleted file mode 100644 index 072d2c2500..0000000000 --- a/lemuroid-app/src/main/res/xml/mobile_settings.xml +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lemuroid-app/src/main/res/xml/mobile_settings_advanced.xml b/lemuroid-app/src/main/res/xml/mobile_settings_advanced.xml deleted file mode 100644 index 90b3b5e79f..0000000000 --- a/lemuroid-app/src/main/res/xml/mobile_settings_advanced.xml +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lemuroid-app/src/main/res/xml/tv_settings.xml b/lemuroid-app/src/main/res/xml/tv_settings.xml index 679f181fd8..ed40e36b46 100644 --- a/lemuroid-app/src/main/res/xml/tv_settings.xml +++ b/lemuroid-app/src/main/res/xml/tv_settings.xml @@ -10,6 +10,7 @@ @@ -21,6 +22,17 @@ app:disableDependentsState="true" android:defaultValue="false"/> + + - -