diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt index b438812d58..2b449beaff 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt @@ -11,6 +11,7 @@ object Settings { SECTION_ROOT(R.string.advanced_settings), SECTION_SYSTEM(R.string.preferences_system), SECTION_RENDERER(R.string.preferences_graphics), + SECTION_FRAME_GEN(R.string.frame_gen), SECTION_PERFORMANCE_STATS(R.string.stats_overlay_options), SECTION_INPUT_OVERLAY(R.string.input_overlay_options), SECTION_SOC_OVERLAY(R.string.soc_overlay_options), diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt index 4838291ae4..d3d487ebb2 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt @@ -21,6 +21,7 @@ import org.yuzu.yuzu_emu.features.settings.model.LongSetting import org.yuzu.yuzu_emu.features.settings.model.ShortSetting import org.yuzu.yuzu_emu.features.settings.model.StringSetting import org.yuzu.yuzu_emu.network.NetDataValidators +import org.yuzu.yuzu_emu.utils.LosslessScalingHelper import org.yuzu.yuzu_emu.utils.NativeConfig /** @@ -65,6 +66,12 @@ abstract class SettingsItem( return NativeLibrary.isFirmwareAvailable() } + if (setting.key in frameGenKeys && + !(LosslessScalingHelper.isInstalled() && LosslessScalingHelper.isSupportedByGpu()) + ) { + return false + } + // Can't edit settings that aren't saveable in per-game config even if they are switchable if (NativeConfig.isPerGameConfigLoaded() && !setting.isSaveable) { return false @@ -89,6 +96,14 @@ abstract class SettingsItem( get() = !setting.global && NativeConfig.isPerGameConfigLoaded() companion object { + private val frameGenKeys = setOf( + BooleanSetting.RENDERER_FRAME_GEN.key, + IntSetting.RENDERER_FRAME_GEN_MULTIPLIER.key, + IntSetting.RENDERER_FRAME_GEN_FLOW_SCALE.key, + BooleanSetting.RENDERER_FRAME_GEN_FP16.key, + BooleanSetting.RENDERER_FRAME_GEN_DUMP_FLOW.key + ) + const val TYPE_HEADER = 0 const val TYPE_SWITCH = 1 const val TYPE_SINGLE_CHOICE = 2 diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt index 0082e425ae..e1684e0115 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt @@ -119,6 +119,25 @@ class SettingsFragment : Fragment() { viewLifecycleOwner, resetState = { settingsViewModel.setShouldShowLosslessInstaller(false) } ) { if (it) losslessDllPickerLauncher.launch(arrayOf("*/*")) } + settingsViewModel.shouldShowLosslessRemoveDialog.collect( + viewLifecycleOwner, + resetState = { settingsViewModel.setShouldShowLosslessRemoveDialog(false) } + ) { + if (it) { + MessageDialogFragment.newInstance( + activity = requireActivity(), + titleId = R.string.lossless_scaling_remove, + descriptionId = R.string.lossless_scaling_remove_confirmation, + positiveButtonTitleId = R.string.lossless_scaling_remove, + positiveAction = { + LosslessScalingHelper.remove() + settingsViewModel.setShouldReloadSettingsList(true) + }, + showNegativeButton = true, + negativeAction = {} + ).show(parentFragmentManager, MessageDialogFragment.TAG) + } + } settingsViewModel.adapterItemChanged.collect( viewLifecycleOwner, resetState = { settingsViewModel.setAdapterItemChanged(-1) } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt index ffb99e4c63..cec5871652 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -79,9 +79,20 @@ class SettingsFragmentPresenter( private fun addFrameGenSettings(sl: ArrayList) { sl.apply { - add(HeaderSetting(R.string.frame_gen)) - val installed = LosslessScalingHelper.isInstalled() + val supported = LosslessScalingHelper.isSupportedByGpu() + + add(HeaderSetting(R.string.lossless_scaling)) + + if (!supported) { + add( + RunnableSetting( + titleId = R.string.frame_gen_unsupported, + descriptionId = R.string.frame_gen_unsupported_description, + isRunnable = false + ) {} + ) + } add( RunnableSetting( @@ -100,26 +111,23 @@ class SettingsFragmentPresenter( ) { settingsViewModel.setShouldShowLosslessInstaller(true) } ) - if (!LosslessScalingHelper.isSupportedByGpu()) { + if (installed) { add( RunnableSetting( - titleId = R.string.frame_gen_unsupported, - descriptionId = R.string.frame_gen_unsupported_description, - isRunnable = false - ) {} + titleId = R.string.lossless_scaling_remove, + descriptionId = R.string.lossless_scaling_remove_description, + isRunnable = !NativeLibrary.isRunning(), + iconId = R.drawable.ic_delete + ) { settingsViewModel.setShouldShowLosslessRemoveDialog(true) } ) - return@apply } - if (!installed) { - return@apply - } + add(HeaderSetting(R.string.frame_gen)) add(BooleanSetting.RENDERER_FRAME_GEN.key) add(IntSetting.RENDERER_FRAME_GEN_MULTIPLIER.key) add(IntSetting.RENDERER_FRAME_GEN_FLOW_SCALE.key) add(BooleanSetting.RENDERER_FRAME_GEN_FP16.key) - add(BooleanSetting.RENDERER_FRAME_GEN_DUMP_FLOW.key) } } @@ -167,6 +175,7 @@ class SettingsFragmentPresenter( MenuTag.SECTION_ROOT -> addConfigSettings(sl) MenuTag.SECTION_SYSTEM -> addSystemSettings(sl) MenuTag.SECTION_RENDERER -> addGraphicsSettings(sl) + MenuTag.SECTION_FRAME_GEN -> addFrameGenSettings(sl) MenuTag.SECTION_PERFORMANCE_STATS -> addPerformanceOverlaySettings(sl) MenuTag.SECTION_SOC_OVERLAY -> addSocOverlaySettings(sl) MenuTag.SECTION_INPUT_OVERLAY -> addInputOverlaySettings(sl) @@ -327,7 +336,14 @@ class SettingsFragmentPresenter( } add(IntSetting.RENDERER_ANTI_ALIASING.key) - addFrameGenSettings(this) + add( + SubmenuSetting( + titleId = R.string.frame_gen, + descriptionId = R.string.frame_gen_submenu_description, + iconId = R.drawable.ic_frames, + menuKey = MenuTag.SECTION_FRAME_GEN + ) + ) add(HeaderSetting(R.string.advanced)) @@ -351,7 +367,6 @@ class SettingsFragmentPresenter( add(BooleanSetting.SKIP_CPU_INNER_INVALIDATION.key) add(BooleanSetting.FIX_BLOOM_EFFECTS.key) add(BooleanSetting.EMULATE_BGR565.key) - add(BooleanSetting.RESCALE_HACK.key) add(BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS.key) add(IntSetting.ANDROID_PIPELINE_WORKERS.key) add(BooleanSetting.RENDERER_ASYNCHRONOUS_GPU_EMULATION.key) @@ -1345,6 +1360,7 @@ class SettingsFragmentPresenter( add(BooleanSetting.DUMP_GUEST_SHADERS.key) add(BooleanSetting.GPU_LOG_SHADER_DUMPS.key) add(BooleanSetting.DUMP_MACROS.key) + add(BooleanSetting.RENDERER_FRAME_GEN_DUMP_FLOW.key) add(BooleanSetting.GPU_LOG_MEMORY_TRACKING.key) add(BooleanSetting.GPU_LOG_DRIVER_DEBUG.key) add(IntSetting.GPU_LOG_RING_BUFFER_SIZE.key) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsViewModel.kt index d9c3a7d9d3..466780577b 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsViewModel.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsViewModel.kt @@ -39,6 +39,9 @@ class SettingsViewModel : ViewModel() { val shouldShowLosslessInstaller: StateFlow get() = _shouldShowLosslessInstaller private val _shouldShowLosslessInstaller = MutableStateFlow(false) + val shouldShowLosslessRemoveDialog: StateFlow get() = _shouldShowLosslessRemoveDialog + private val _shouldShowLosslessRemoveDialog = MutableStateFlow(false) + val sliderProgress: StateFlow get() = _sliderProgress private val _sliderProgress = MutableStateFlow(-1) @@ -92,6 +95,10 @@ class SettingsViewModel : ViewModel() { _shouldShowLosslessInstaller.value = value } + fun setShouldShowLosslessRemoveDialog(value: Boolean) { + _shouldShowLosslessRemoveDialog.value = value + } + fun setSliderTextValue(value: Float, units: String) { _sliderProgress.value = value.toInt() _sliderTextValue.value = String.format( diff --git a/src/android/app/src/main/jni/android_config.cpp b/src/android/app/src/main/jni/android_config.cpp index e016322c23..6548667de4 100644 --- a/src/android/app/src/main/jni/android_config.cpp +++ b/src/android/app/src/main/jni/android_config.cpp @@ -33,8 +33,8 @@ void AndroidConfig::SaveAllValues() { } void AndroidConfig::ReadAndroidValues() { + ReadAndroidUIValues(); if (global) { - ReadAndroidUIValues(); ReadUIValues(); BeginGroup(Settings::TranslateCategory(Settings::Category::DataStorage)); Settings::values.ext_content_from_game_dirs = ReadBooleanSetting( @@ -223,8 +223,8 @@ void AndroidConfig::ReadAndroidControlValues() { } void AndroidConfig::SaveAndroidValues() { + SaveAndroidUIValues(); if (global) { - SaveAndroidUIValues(); SaveUIValues(); SaveOverlayValues(); } diff --git a/src/android/app/src/main/jni/android_settings.h b/src/android/app/src/main/jni/android_settings.h index 304ff62f07..7cc3ad22d5 100644 --- a/src/android/app/src/main/jni/android_settings.h +++ b/src/android/app/src/main/jni/android_settings.h @@ -147,7 +147,7 @@ namespace AndroidSettings { &show_performance_overlay}; - Settings::Setting pipeline_worker_count{linkage, 4, "pipeline_worker_count", + Settings::SwitchableSetting pipeline_worker_count{linkage, 2, "pipeline_worker_count", Settings::Category::Android, Settings::Specialization::Default, true, diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index ac90874943..954c376446 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -299,23 +299,24 @@ GPU driver manager Install alternative drivers for potentially better performance or accuracy Frame generation - Insert interpolated frames between rendered ones using Lossless Scaling. Forces FIFO presentation while enabled, since other modes discard the generated frames. Adds about one frame of latency. + Manage and configure frame generation + Insert interpolated frames between rendered ones using Lossless Scaling. Forces FIFO presentation while enabled. Frame multiplier How many frames to display for each rendered frame. Higher values cost proportionally more GPU time. - 2x (one generated frame) - 3x (two generated frames) - 4x (three generated frames) + 2x + 3x + 4x Motion estimation resolution Resolution of the optical flow pass, as a fraction of the output. Lowering it is the cheapest way to reclaim performance. Half precision shaders - Use the 16-bit shader variant shipped in Lossless.dll. Much faster on Adreno. Falls back automatically if the driver or the file lacks it. + Use the 16-bit shader variant shipped in Lossless.dll. Falls back automatically if the driver or the file lacks it. Dump generated frame Write the optical flow mip levels and the interpolated frame to the lossless/debug folder once, for troubleshooting Frame generation unavailable This GPU driver does not support the Vulkan memory model, which the Lossless Scaling shaders require. Optional. Provide your own Lossless.dll to enable frame generation later Install Lossless.dll - Frame generation needs your own copy of Lossless.dll from Lossless Scaling + Frame generation needs your own legal copy of Lossless.dll from Lossless Scaling Select a different copy of Lossless.dll Frame generation Supported @@ -327,6 +328,8 @@ Lossless.dll is installed and contains every shader frame generation needs. Replace Remove + Delete the installed Lossless.dll and its prepared shaders + Frame generation will stop working until you install Lossless.dll again. Your original file is not affected. Preparing frame generation shaders… Lossless.dll installed successfully Could not install Lossless.dll diff --git a/src/common/settings.h b/src/common/settings.h index 9ed33556c1..4466714fdf 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -352,7 +352,7 @@ struct Values { true}; SwitchableSetting scaling_filter{linkage, - ScalingFilter::Bilinear, + ScalingFilter::NearestNeighbor, "scaling_filter", Category::Renderer, Specialization::Default, @@ -389,7 +389,7 @@ struct Values { true}; SwitchableSetting frame_gen{linkage, false, "frame_gen", Category::Renderer, - Specialization::Default, true, true}; + Specialization::Default, true, false}; SwitchableSetting frame_gen_multiplier{linkage, 2, @@ -399,11 +399,11 @@ struct Values { Category::Renderer, Specialization::Countable, true, - true, + false, &frame_gen}; SwitchableSetting frame_gen_flow_scale{linkage, - 100, + 75, 25, 100, "frame_gen_flow_scale", @@ -415,7 +415,7 @@ struct Values { &frame_gen}; SwitchableSetting frame_gen_fp16{linkage, true, "frame_gen_fp16", Category::Renderer, - Specialization::Default, true, true, &frame_gen}; + Specialization::Default, true, false, &frame_gen}; SwitchableSetting frame_gen_dump_flow{linkage, false, "frame_gen_dump_flow", Category::Renderer}; @@ -601,13 +601,8 @@ struct Values { SwitchableSetting emulate_bgr565{linkage, false, "emulate_bgr565", Category::RendererHacks}; - SwitchableSetting rescale_hack{linkage, -#ifdef __ANDROID__ - true, -#else - false, -#endif - "rescale_hack", Category::RendererHacks}; + SwitchableSetting rescale_hack{linkage, false, "rescale_hack", + Category::RendererHacks}; SwitchableSetting enable_gpu_buffer_readback{linkage, false, "enable_gpu_buffer_readback", diff --git a/src/yuzu/configuration/shared_widget.cpp b/src/yuzu/configuration/shared_widget.cpp index ce11763f91..5f28299065 100644 --- a/src/yuzu/configuration/shared_widget.cpp +++ b/src/yuzu/configuration/shared_widget.cpp @@ -772,10 +772,24 @@ Builder::Builder(QWidget* parent_, bool runtime_lock_) Builder::~Builder() = default; +static bool IsAndroidOnly(const Settings::BasicSetting& setting) { + const auto id = setting.Id(); + return id == Settings::values.frame_gen.Id() || + id == Settings::values.frame_gen_multiplier.Id() || + id == Settings::values.frame_gen_flow_scale.Id() || + id == Settings::values.frame_gen_fp16.Id() || + id == Settings::values.frame_gen_dump_flow.Id() || + id == Settings::values.emulate_bgr565.Id(); +} + Widget* Builder::BuildWidget(Settings::BasicSetting* setting, std::vector>& apply_funcs, RequestType request, bool managed, float multiplier, Settings::BasicSetting* other_setting, const QString& suffix) const { + if (IsAndroidOnly(*setting)) { + return nullptr; + } + if (!Settings::IsConfiguringGlobal() && !setting->Switchable()) { return nullptr; }