android: Enhance FPS Overlay with more customizable options

- Now the fps follows theme color set in settings
- Added the ability to toggle stats on and off depending on user preference
- Now you are able to change the fps position and add a background behind it for easier reding

New added stats for the overlay are

FPS
FRAMETIME,
SPEED,
APP_RAM_USAGE,
SYSTEM_RAM_USAGE,
BATTERY_TEMPERATURE,
This commit is contained in:
Briar 2025-04-13 05:36:30 +02:00
parent 50ac5e935a
commit fe51be43c1
15 changed files with 455 additions and 141 deletions

View file

@ -26,7 +26,15 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
SHOW_PERFORMANCE_OVERLAY("show_performance_overlay"),
SHOW_INPUT_OVERLAY("show_input_overlay"),
TOUCHSCREEN("touchscreen"),
SHOW_THERMAL_OVERLAY("show_thermal_overlay");
SHOW_THERMAL_OVERLAY("show_thermal_overlay"),
SHOW_FPS("show_fps"),
SHOW_FRAMETIME("show_frame_time"),
SHOW_SPEED("show_speed"),
SHOW_APP_RAM_USAGE("show_app_ram_usage"),
SHOW_SYSTEM_RAM_USAGE("show_system_ram_usage"),
SHOW_BAT_TEMPERATURE("show_bat_temperature"),
OVERLAY_BACKGROUND("overlay_background"),;
override fun getBoolean(needsGlobal: Boolean): Boolean =
NativeConfig.getBoolean(key, needsGlobal)

View file

@ -26,6 +26,7 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
OVERLAY_OPACITY("control_opacity"),
LOCK_DRAWER("lock_drawer"),
VERTICAL_ALIGNMENT("vertical_alignment"),
PERF_OVERLAY_POSITION("perf_overlay_position"),
FSR_SHARPENING_SLIDER("fsr_sharpening_slider");
override fun getInt(needsGlobal: Boolean): Int = NativeConfig.getInt(key, needsGlobal)

View file

@ -12,6 +12,7 @@ object Settings {
SECTION_ROOT(R.string.advanced_settings),
SECTION_SYSTEM(R.string.preferences_system),
SECTION_RENDERER(R.string.preferences_graphics),
SECTION_PERFORMANCE_STATS(R.string.show_stats_overlay),
SECTION_AUDIO(R.string.preferences_audio),
SECTION_INPUT(R.string.preferences_controls),
SECTION_INPUT_PLAYER_ONE,
@ -32,6 +33,7 @@ object Settings {
const val PREF_FIRST_APP_LAUNCH = "FirstApplicationLaunch"
const val PREF_SHOULD_SHOW_PRE_ALPHA_WARNING = "ShouldShowPreAlphaWarning"
const val PREF_MEMORY_WARNING_SHOWN = "MemoryWarningShown"
const val SECTION_STATS_OVERLAY = "Stats Overlay"
// Deprecated input overlay preference keys
const val PREF_CONTROL_SCALE = "controlScale"

View file

@ -220,6 +220,71 @@ abstract class SettingsItem(
valuesId = R.array.rendererResolutionValues
)
)
put(
SwitchSetting(
BooleanSetting.SHOW_PERFORMANCE_OVERLAY,
R.string.enable_stats_overlay_,
descriptionId = R.string.stats_overlay_options_description
)
)
put(
SwitchSetting(
BooleanSetting.OVERLAY_BACKGROUND,
R.string.overlay_background,
descriptionId = R.string.overlay_background_description
)
)
put(
SingleChoiceSetting(
IntSetting.PERF_OVERLAY_POSITION,
titleId = R.string.overlay_position,
descriptionId = R.string.overlay_position_description,
choicesId = R.array.statsPosition,
valuesId = R.array.staticThemeValues
)
)
put(
SwitchSetting(
BooleanSetting.SHOW_FPS,
R.string.show_fps,
descriptionId = R.string.show_fps_description
)
)
put(
SwitchSetting(
BooleanSetting.SHOW_FRAMETIME,
R.string.show_frametime,
descriptionId = R.string.show_frametime_description
)
)
put(
SwitchSetting(
BooleanSetting.SHOW_SPEED,
R.string.show_speed,
descriptionId = R.string.show_speed_description
)
)
put(
SwitchSetting(
BooleanSetting.SHOW_APP_RAM_USAGE,
R.string.show_app_ram_usage,
descriptionId = R.string.show_app_ram_usage_description
)
)
put(
SwitchSetting(
BooleanSetting.SHOW_SYSTEM_RAM_USAGE,
R.string.show_system_ram_usage,
descriptionId = R.string.show_system_ram_usage_description
)
)
put(
SwitchSetting(
BooleanSetting.SHOW_BAT_TEMPERATURE,
R.string.show_bat_temperature,
descriptionId = R.string.show_bat_temperature_description
)
)
put(
SingleChoiceSetting(
IntSetting.RENDERER_VSYNC,

View file

@ -88,6 +88,7 @@ class SettingsFragmentPresenter(
MenuTag.SECTION_ROOT -> addConfigSettings(sl)
MenuTag.SECTION_SYSTEM -> addSystemSettings(sl)
MenuTag.SECTION_RENDERER -> addGraphicsSettings(sl)
MenuTag.SECTION_PERFORMANCE_STATS -> addPerfomanceOverlaySettings(sl)
MenuTag.SECTION_AUDIO -> addAudioSettings(sl)
MenuTag.SECTION_INPUT -> addInputSettings(sl)
MenuTag.SECTION_INPUT_PLAYER_ONE -> addInputPlayer(sl, 0)
@ -127,6 +128,15 @@ class SettingsFragmentPresenter(
menuKey = MenuTag.SECTION_RENDERER
)
)
if (!NativeConfig.isPerGameConfigLoaded())
add(
SubmenuSetting(
titleId = R.string.stats_overlay_options,
descriptionId = R.string.stats_overlay_options_description,
iconId = R.drawable.ic_frames,
menuKey = MenuTag.SECTION_PERFORMANCE_STATS
)
)
add(
SubmenuSetting(
titleId = R.string.preferences_audio,
@ -187,6 +197,23 @@ class SettingsFragmentPresenter(
}
}
private fun addPerfomanceOverlaySettings(sl: ArrayList<SettingsItem>) {
sl.apply {
add(HeaderSetting(R.string.stats_overlay_customization))
add(BooleanSetting.SHOW_PERFORMANCE_OVERLAY.key)
add(BooleanSetting.OVERLAY_BACKGROUND.key)
add(IntSetting.PERF_OVERLAY_POSITION.key)
add(HeaderSetting(R.string.stats_overlay_items))
add(BooleanSetting.SHOW_FPS.key)
add(BooleanSetting.SHOW_FRAMETIME.key)
add(BooleanSetting.SHOW_SPEED.key)
add(BooleanSetting.SHOW_APP_RAM_USAGE.key)
add(BooleanSetting.SHOW_SYSTEM_RAM_USAGE.key)
add(BooleanSetting.SHOW_BAT_TEMPERATURE.key)
}
}
private fun addAudioSettings(sl: ArrayList<SettingsItem>) {
sl.apply {
add(IntSetting.AUDIO_OUTPUT_ENGINE.key)

View file

@ -4,18 +4,29 @@
package org.yuzu.yuzu_emu.fragments
import android.annotation.SuppressLint
import android.app.ActivityManager
import android.app.AlertDialog
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.ActivityInfo
import android.content.res.Configuration
import android.graphics.Color
import android.net.Uri
import android.os.BatteryManager
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.SystemClock
import android.util.Rational
import android.view.*
import android.view.Gravity
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.Surface
import android.view.SurfaceHolder
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.TextView
import android.widget.Toast
@ -26,7 +37,6 @@ import androidx.core.graphics.Insets
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import androidx.drawerlayout.widget.DrawerLayout
import androidx.drawerlayout.widget.DrawerLayout.DrawerListener
import androidx.fragment.app.Fragment
@ -36,6 +46,7 @@ import androidx.navigation.fragment.navArgs
import androidx.window.layout.FoldingFeature
import androidx.window.layout.WindowInfoTracker
import androidx.window.layout.WindowLayoutInfo
import com.google.android.material.color.MaterialColors
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.slider.Slider
import org.yuzu.yuzu_emu.HomeNavigationDirections
@ -51,28 +62,28 @@ import org.yuzu.yuzu_emu.features.settings.model.Settings.EmulationOrientation
import org.yuzu.yuzu_emu.features.settings.model.Settings.EmulationVerticalAlignment
import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
import org.yuzu.yuzu_emu.model.DriverViewModel
import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.model.EmulationViewModel
import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.overlay.model.OverlayControl
import org.yuzu.yuzu_emu.overlay.model.OverlayLayout
import org.yuzu.yuzu_emu.utils.*
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
import org.yuzu.yuzu_emu.utils.FileUtil
import org.yuzu.yuzu_emu.utils.GameHelper
import org.yuzu.yuzu_emu.utils.GameIconUtils
import org.yuzu.yuzu_emu.utils.Log
import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.ViewUtils
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import java.lang.NullPointerException
import android.content.BroadcastReceiver
import android.content.Intent
import android.content.IntentFilter
import android.os.BatteryManager
import android.util.TypedValue
import android.app.ActivityManager
import android.graphics.Color
import android.os.Debug
import org.yuzu.yuzu_emu.utils.collect
import java.io.File
class EmulationFragment : Fragment(), SurfaceHolder.Callback {
private lateinit var emulationState: EmulationState
private var emulationActivity: EmulationActivity? = null
private var perfStatsUpdater: (() -> Unit)? = null
private var thermalStatsUpdater: (() -> Unit)? = null
private var batteryReceiverRegistered: Boolean = false
private lateinit var cpuBackend: String
private lateinit var gpuDriver: String
private var _binding: FragmentEmulationBinding? = null
private val binding get() = _binding!!
@ -198,8 +209,10 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
})
binding.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
binding.inGameMenu.getHeaderView(0).findViewById<TextView>(R.id.text_game_title).text =
game.title
binding.inGameMenu.getHeaderView(0).apply {
val titleView = findViewById<TextView>(R.id.text_game_title)
titleView.text = game.title
}
binding.inGameMenu.menu.findItem(R.id.menu_lock_drawer).apply {
val lockMode = IntSetting.LOCK_DRAWER.getInt()
@ -375,9 +388,23 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
emulationState.updateSurface()
// Setup overlays
updateShowFpsOverlay()
val temperature = getBatteryTemperature(requireContext())
updateThermalOverlay(temperature)
updateshowStatsOvelray()
// Re update binding when the specs values get initialized properly
binding.inGameMenu.getHeaderView(0).apply {
val titleView = findViewById<TextView>(R.id.text_game_title)
val cpuBackendLabel = findViewById<TextView>(R.id.cpu_backend)
val gpuvendorLabel = findViewById<TextView>(R.id.gpu_vendor)
titleView.text = game.title
cpuBackendLabel.text = NativeLibrary.getCpuBackend()
gpuvendorLabel.text = NativeLibrary.getGpuDriver()
}
val position = IntSetting.PERF_OVERLAY_POSITION.getInt()
updateStatsPosition(position)
}
}
emulationViewModel.isEmulationStopping.collect(viewLifecycleOwner) {
@ -385,7 +412,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
binding.loadingText.setText(R.string.shutting_down)
ViewUtils.showView(binding.loadingIndicator)
ViewUtils.hideView(binding.inputContainer)
ViewUtils.hideView(binding.showFpsText)
ViewUtils.hideView(binding.showStatsOverlayText)
}
}
emulationViewModel.drawerOpen.collect(viewLifecycleOwner) {
@ -466,23 +493,11 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
override fun onPause() {
if (emulationState.isRunning && emulationActivity?.isInPictureInPictureMode != true) {
emulationState.pause()
}
context?.let {
if (batteryReceiverRegistered) {
it.unregisterReceiver(batteryReceiver)
batteryReceiverRegistered = false
}
}
super.onPause()
}
override fun onDestroyView() {
context?.let {
if (batteryReceiverRegistered) {
it.unregisterReceiver(batteryReceiver)
batteryReceiverRegistered = false
}
}
super.onDestroyView()
_binding = null
}
@ -493,11 +508,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
override fun onResume() {
super.onResume()
if (!batteryReceiverRegistered) {
val filter = IntentFilter(Intent.ACTION_BATTERY_CHANGED)
context?.registerReceiver(batteryReceiver, filter)
batteryReceiverRegistered = true
}
// If the overlay is enabled, we need to update the position if changed
val position = IntSetting.PERF_OVERLAY_POSITION.getInt()
updateStatsPosition(position)
}
private fun resetInputOverlay() {
@ -508,37 +521,90 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
}
@SuppressLint("DefaultLocale")
private fun updateShowFpsOverlay() {
private fun updateshowStatsOvelray() {
val showOverlay = BooleanSetting.SHOW_PERFORMANCE_OVERLAY.getBoolean()
binding.showFpsText.setTextColor(Color.parseColor("#A146FF"))
binding.showFpsText.setVisible(showOverlay)
binding.showStatsOverlayText.apply {
setTextColor(
MaterialColors.getColor(
this,
com.google.android.material.R.attr.colorPrimary
)
)
}
binding.showStatsOverlayText.setVisible(showOverlay)
if (showOverlay) {
val SYSTEM_FPS = 0
val FPS = 1
val FRAMETIME = 2
val SPEED = 3
val sb = StringBuilder()
perfStatsUpdater = {
if (emulationViewModel.emulationStarted.value &&
!emulationViewModel.isEmulationStopping.value
) {
sb.setLength(0) // Clear the StringBuilder to avoid recurring appends
val perfStats = NativeLibrary.getPerfStats()
val cpuBackend = NativeLibrary.getCpuBackend()
val gpuDriver = NativeLibrary.getGpuDriver()
// Get memory info
val mi = ActivityManager.MemoryInfo()
val activityManager =
requireContext().getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
activityManager.getMemoryInfo(mi)
// Calculate used memory
val usedMegs = (mi.totalMem - mi.availMem) / 1048576L // Convert bytes to megabytes
if (_binding != null) {
binding.showFpsText.text = String.format(
"%.1f FPS • %d MB • %s/%s",
perfStats[FPS], usedMegs, cpuBackend, gpuDriver
if (BooleanSetting.SHOW_FPS.getBoolean(NativeConfig.isPerGameConfigLoaded())) {
sb.append(String.format("FPS: %d", (perfStats[FPS] + 0.5).toInt()))
// perfStats[FPS], usedMegs, cpuBackend, gpuDriver
if (BooleanSetting.SHOW_FRAMETIME.getBoolean(NativeConfig.isPerGameConfigLoaded())) {
if (sb.isNotEmpty()) sb.append(" | ")
sb.append(
String.format(
"FT: %.1fms",
(perfStats[FRAMETIME] * 1000.0f).toFloat()
)
)
}
if (BooleanSetting.SHOW_SPEED.getBoolean(NativeConfig.isPerGameConfigLoaded())) {
if (sb.isNotEmpty()) sb.append(" | ")
sb.append(
String.format(
"Speed: %d%%",
(perfStats[SPEED] * 100.0 + 0.5).toInt()
)
)
}
if (BooleanSetting.SHOW_APP_RAM_USAGE.getBoolean(NativeConfig.isPerGameConfigLoaded())) {
if (sb.isNotEmpty()) sb.append(" | ")
val appRamUsage =
File("/proc/self/statm").readLines()[0].split(' ')[1].toLong() * 4096 / 1000000
sb.append("Process RAM: $appRamUsage MB")
}
if (BooleanSetting.SHOW_SYSTEM_RAM_USAGE.getBoolean(NativeConfig.isPerGameConfigLoaded())) {
if (sb.isNotEmpty()) sb.append(" | ")
context?.let { ctx ->
val activityManager =
ctx.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
val memInfo = ActivityManager.MemoryInfo()
activityManager.getMemoryInfo(memInfo)
val usedRamMB = (memInfo.totalMem - memInfo.availMem) / 1048576L
sb.append("RAM: $usedRamMB MB")
}
}
if (BooleanSetting.SHOW_BAT_TEMPERATURE.getBoolean(NativeConfig.isPerGameConfigLoaded())) {
if (sb.isNotEmpty()) sb.append(" | ")
val batteryTemp = getBatteryTemperature()
val tempF = celsiusToFahrenheit(batteryTemp)
sb.append(String.format("%.1f°C/%.1f°F", batteryTemp, tempF))
}
if (BooleanSetting.OVERLAY_BACKGROUND.getBoolean(NativeConfig.isPerGameConfigLoaded())) {
binding.showStatsOverlayText.setBackgroundResource(R.color.yuzu_transparent_black)
} else {
binding.showStatsOverlayText.setBackgroundResource(0)
}
binding.showStatsOverlayText.text = sb.toString()
}
}
perfStatsUpdateHandler.postDelayed(perfStatsUpdater!!, 800)
}
@ -551,18 +617,55 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
}
private val batteryReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
intent?.let {
if (it.action == Intent.ACTION_BATTERY_CHANGED) {
val temperature = getBatteryTemperature(context!!)
updateThermalOverlay(temperature)
private fun updateStatsPosition(position: Int) {
val params = binding.showStatsOverlayText.layoutParams as FrameLayout.LayoutParams
when (position) {
0 -> {
params.gravity = (Gravity.TOP or Gravity.START)
params.setMargins(resources.getDimensionPixelSize(R.dimen.spacing_large), 0, 0, 0)
}
}
}
}
private fun updateThermalOverlay(temperature: Float) {
1 -> {
params.gravity = (Gravity.TOP or Gravity.CENTER_HORIZONTAL)
}
2 -> {
params.gravity = (Gravity.TOP or Gravity.END)
params.setMargins(0, 0, resources.getDimensionPixelSize(R.dimen.spacing_large), 0)
}
3 -> {
params.gravity = (Gravity.BOTTOM or Gravity.START)
params.setMargins(resources.getDimensionPixelSize(R.dimen.spacing_large), 0, 0, 0)
}
4 -> {
params.gravity = (Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL)
}
5 -> {
params.gravity = (Gravity.BOTTOM or Gravity.END)
params.setMargins(0, 0, resources.getDimensionPixelSize(R.dimen.spacing_large), 0)
}
}
}
private fun getBatteryTemperature(): Float {
try {
val batteryIntent = requireContext().registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
// Temperature in tenths of a degree Celsius
val temperature = batteryIntent?.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0) ?: 0
// Convert to degrees Celsius
return temperature / 10.0f
} catch (e: Exception) {
return 0.0f
}
}
private fun celsiusToFahrenheit(celsius: Float): Float {
return (celsius * 9 / 5) + 32
}
private fun updateThermalOverlay(temperature: Float) {
if (BooleanSetting.SHOW_THERMAL_OVERLAY.getBoolean() &&
emulationViewModel.emulationStarted.value &&
!emulationViewModel.isEmulationStopping.value
@ -581,17 +684,9 @@ private fun updateThermalOverlay(temperature: Float) {
binding.showThermalsText.setTextColor(color)
binding.showThermalsText.text = String.format("%.1f°C • %.1f°F", temperature, fahrenheit)
}
}
private fun getBatteryTemperature(context: Context): Float {
val intent: Intent? = context.registerReceiver(
null,
IntentFilter(Intent.ACTION_BATTERY_CHANGED)
)
val temperature = intent?.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0) ?: 0
return temperature / 10.0f
}
@SuppressLint("SourceLockedOrientationActivity")
private fun updateOrientation() {
emulationActivity?.let {
@ -717,10 +812,8 @@ private fun getBatteryTemperature(context: Context): Float {
popup.menuInflater.inflate(R.menu.menu_overlay_options, popup.menu)
popup.menu.apply {
findItem(R.id.menu_toggle_fps).isChecked =
findItem(R.id.menu_show_stats_overlay).isChecked =
BooleanSetting.SHOW_PERFORMANCE_OVERLAY.getBoolean()
findItem(R.id.thermal_indicator).isChecked =
BooleanSetting.SHOW_THERMAL_OVERLAY.getBoolean()
findItem(R.id.menu_rel_stick_center).isChecked =
BooleanSetting.JOYSTICK_REL_CENTER.getBoolean()
findItem(R.id.menu_dpad_slide).isChecked = BooleanSetting.DPAD_SLIDE.getBoolean()
@ -733,34 +826,12 @@ private fun getBatteryTemperature(context: Context): Float {
popup.setOnDismissListener { NativeConfig.saveGlobalConfig() }
popup.setOnMenuItemClickListener {
when (it.itemId) {
R.id.menu_toggle_fps -> {
R.id.menu_show_stats_overlay -> {
it.isChecked = !it.isChecked
BooleanSetting.SHOW_PERFORMANCE_OVERLAY.setBoolean(it.isChecked)
updateShowFpsOverlay()
updateshowStatsOvelray()
true
}
R.id.thermal_indicator -> {
it.isChecked = !it.isChecked
BooleanSetting.SHOW_THERMAL_OVERLAY.setBoolean(it.isChecked)
if (it.isChecked) {
val temperature = getBatteryTemperature(requireContext())
updateThermalOverlay(temperature)
if (!batteryReceiverRegistered) {
val filter = IntentFilter(Intent.ACTION_BATTERY_CHANGED)
context?.registerReceiver(batteryReceiver, filter)
batteryReceiverRegistered = true
}
} else {
if (batteryReceiverRegistered) {
context?.unregisterReceiver(batteryReceiver)
batteryReceiverRegistered = false
}
binding.showThermalsText.text = ""
}
true
}
R.id.menu_edit_overlay -> {
binding.drawerLayout.close()
binding.surfaceInputOverlay.requestFocus()
@ -951,7 +1022,8 @@ private fun getBatteryTemperature(context: Context): Float {
right = cutInsets.right
}
v.updatePadding(left = left, top = cutInsets.top, right = right)
v.setPadding(left, cutInsets.top, right, 0)
windowInsets
}
}

View file

@ -66,9 +66,23 @@ struct Values {
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_thermal_overlay{linkage, false, "show_thermal_overlay",
Settings::Category::Overlay};
Settings::Category::Overlay, Settings::Specialization::Paired, true , true};
Settings::Setting<bool> overlay_background{linkage, false, "overlay_background",
Settings::Category::Overlay, Settings::Specialization::Default, true , true, &show_performance_overlay};
Settings::Setting<s32> perf_overlay_position{linkage, 0, "perf_overlay_position",
Settings::Category::Overlay, Settings::Specialization::Default, true , true, &show_performance_overlay};
Settings::Setting<bool> show_fps{linkage, true, "show_fps",
Settings::Category::Overlay, Settings::Specialization::Default, true , true, &show_performance_overlay};
Settings::Setting<bool> show_frame_time{linkage, false, "show_frame_time",
Settings::Category::Overlay, Settings::Specialization::Default, true , true, &show_performance_overlay};
Settings::Setting<bool> show_speed{linkage, true, "show_speed",
Settings::Category::Overlay, Settings::Specialization::Default, true , true, &show_performance_overlay};
Settings::Setting<bool> show_app_ram_usage{linkage, false, "show_app_ram_usage",
Settings::Category::Overlay, Settings::Specialization::Default, true , true, &show_performance_overlay};
Settings::Setting<bool> show_system_ram_usage{linkage, false, "show_system_ram_usage",
Settings::Category::Overlay, Settings::Specialization::Default, true , true, &show_performance_overlay};
Settings::Setting<bool> show_bat_temperature{linkage, false, "show_bat_temperature",
Settings::Category::Overlay, Settings::Specialization::Default, true , true, &show_performance_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};

View file

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#00000000"
android:strokeColor="#FF000000"
android:strokeWidth="1"
android:pathData="M4,4 L4,20 L20,20" />
<path
android:fillColor="#00000000"
android:strokeColor="#FF000000"
android:strokeWidth="2"
android:pathData="M4,16 L8,12 L12,14 L16,8 L20,10" />
<path
android:fillColor="#FF000000"
android:pathData="M4,16 C3.45,16 3,15.55 3,15 C3,14.45 3.45,14 4,14 C4.55,14 5,14.45 5,15 C5,15.55 4.55,16 4,16" />
<path
android:fillColor="#FF000000"
android:pathData="M8,12 C7.45,12 7,11.55 7,11 C7,10.45 7.45,10 8,10 C8.55,10 9,10.45 9,11 C9,11.55 8.55,12 8,12" />
<path
android:fillColor="#FF000000"
android:pathData="M12,14 C11.45,14 11,13.55 11,13 C11,12.45 11.45,12 12,12 C12.55,12 13,12.45 13,13 C13,13.55 12.55,14 12,14" />
<path
android:fillColor="#FF000000"
android:pathData="M16,8 C15.45,8 15,7.55 15,7 C15,6.45 15.45,6 16,6 C16.55,6 17,6.45 17,7 C17,7.55 16.55,8 16,8" />
<path
android:fillColor="#FF000000"
android:pathData="M20,10 C19.45,10 19,9.55 19,9 C19,8.45 19.45,8 20,8 C20.55,8 21,8.45 21,9 C21,9.55 20.55,10 20,10" />
</vector>

View file

@ -140,15 +140,13 @@
android:id="@+id/overlay_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginHorizontal="20dp"
android:fitsSystemWindows="true">
android:fitsSystemWindows="false">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/show_fps_text"
android:id="@+id/show_stats_overlay_text"
style="@style/TextAppearance.Material3.BodySmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:clickable="false"
android:focusable="false"
android:textColor="@android:color/white"

View file

@ -1,14 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.textview.MaterialTextView
xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="24dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/text_game_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:textAppearance="?attr/textAppearanceHeadlineMedium"
android:textColor="?attr/colorOnSurface"
android:textAlignment="viewStart"
tools:text="Super Mario Odyssey" />
android:layout_marginBottom="8dp"
tools:text="text_game_title" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.google.android.material.textview.MaterialTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?attr/textAppearanceBodyMedium"
android:textColor="?attr/colorOnSurfaceVariant"
android:textAlignment="viewStart"
android:layout_marginEnd="4dp"
android:text="System Info:" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/cpu_backend"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?attr/textAppearanceBodyMedium"
android:textColor="?attr/colorOnSurfaceVariant"
android:textAlignment="viewStart"
tools:text="cpu_backend" />
<com.google.android.material.textview.MaterialTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?attr/textAppearanceBodyMedium"
android:textColor="?attr/colorOnSurfaceVariant"
android:layout_marginStart="4dp"
android:layout_marginEnd="4dp"
android:text="|" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/gpu_vendor"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?attr/textAppearanceBodyMedium"
android:textColor="?attr/colorOnSurfaceVariant"
android:textAlignment="viewStart"
tools:text="gpu_vendor" />
</LinearLayout>
</LinearLayout>

View file

@ -2,13 +2,8 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/menu_toggle_fps"
android:title="@string/emulation_fps_counter"
android:checkable="true" />
<item
android:id="@+id/thermal_indicator"
android:title="@string/emulation_thermal_indicator"
android:id="@+id/menu_show_stats_overlay"
android:title="@string/show_stats_overlay"
android:checkable="true" />
<item

View file

@ -227,6 +227,7 @@
<color name="yuzu_surfaceTint_gray">#B7B7B7</color>
<!-- Common Colors Across All Themes -->
<color name="yuzu_transparent_black">#80000000</color>
<color name="yuzu_outlineVariant">#C6C5D0</color>
<color name="yuzu_error">#FFB4AB</color>
<color name="yuzu_errorContainer">#93000A</color>

View file

@ -183,6 +183,23 @@
<item>2</item>
</integer-array>
<string-array name="statsPosition">
<item>@string/overlay_position_top_left</item>
<item>@string/overlay_position_center_top</item>
<item>@string/overlay_position_top_right</item>
<item>@string/overlay_position_bottom_left</item>
<item>@string/overlay_position_center_bottom</item>
<item>@string/overlay_position_bottom_right</item>
</string-array>
<integer-array name="statsPositionValues">
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
</integer-array>
<string-array name="cpuBackendArm64Names">
<item>@string/cpu_backend_dynarmic</item>
<item>@string/cpu_backend_nce</item>

View file

@ -9,6 +9,37 @@
<string name="notice_notification_channel_description">Shows notifications when something goes wrong.</string>
<string name="notification_permission_not_granted">Notification permission not granted!</string>
<!-- Stats Overlay settings -->
<string name="show_stats_overlay">ShoW Performance Stats Overlay</string>
<string name="stats_overlay_customization">Customization</string>
<string name="stats_overlay_items">Visibility</string>
<string name="stats_overlay_options">Overlay</string>
<string name="enable_stats_overlay_">Enable Performance Stats Overlay</string>
<string name="stats_overlay_options_description">Configure what information is shown in the performance stats overlay</string>
<string name="show_fps">Show FPS</string>
<string name="show_fps_description">Display current frames per second</string>
<string name="show_frametime">Show Frametime</string>
<string name="show_frametime_description">Display current frametime</string>
<string name="show_speed">Show Speed</string>
<string name="show_speed_description">Display current emulation speed percentage</string>
<string name="show_app_ram_usage">Show App Memory Usage</string>
<string name="show_app_ram_usage_description">Display the amount of RAM getting used by the emulator</string>
<string name="show_system_ram_usage">Show System Memory Usage</string>
<string name="show_system_ram_usage_description">Display the amount of RAM getting used by the system</string>
<string name="show_bat_temperature">Show Battery Temperature</string>
<string name="show_bat_temperature_description">Display current Battery temperature in Celsius and Fahrenheit</string>
<string name="overlay_position">Overlay Position</string>
<string name="overlay_position_description">Choose where the performance stats overlay is displayed on the screen</string>
<string name="overlay_position_top_left">Top Left</string>
<string name="overlay_position_top_right">Top Right</string>
<string name="overlay_position_bottom_left">Bottom Left</string>
<string name="overlay_position_bottom_right">Bottom Right</string>
<string name="overlay_position_center_top">Center Top</string>
<string name="overlay_position_center_bottom">Center Bottom</string>
<string name="overlay_background">Overlay Background</string>
<string name="overlay_background_description">Adds a background behind the overlay for easier reading</string>
<!-- Setup strings -->
<string name="welcome">Welcome!</string>
<string name="welcome_description">Learn how to setup &lt;b>eden&lt;/b> and jump into emulation.</string>

View file

@ -229,6 +229,7 @@
<color name="yuzu_onErrorContainer">#410002</color>
<color name="yuzu_shadow">#000000</color>
<color name="yuzu_scrim">#000000</color>
<color name="yuzu_transparent_black">#80000000</color>
<!-- Values used in dark mode but here are jsut white / black values-->
<color name="yuzu_onPrimary_blue">#FFFFFF</color>
<color name="yuzu_onSecondary_blue">#FFFFFF</color>