diff --git a/assets/languages/en/Options.xml b/assets/languages/en/Options.xml
index 1cde775d71..39be41cb80 100644
--- a/assets/languages/en/Options.xml
+++ b/assets/languages/en/Options.xml
@@ -206,6 +206,9 @@
Offset in Charter
If checked, this will enable the Song Offset option in the Chart Editor too.
+
+ Legacy Memory Counter
+ If checked, the memory counter will show the Haxe GC memory usage and its peak (the original behavior) instead of the working set memory seen in Task Manager.
\ No newline at end of file
diff --git a/assets/languages/es/Options.xml b/assets/languages/es/Options.xml
index 60ad120cd9..1f9bb0517d 100644
--- a/assets/languages/es/Options.xml
+++ b/assets/languages/es/Options.xml
@@ -180,6 +180,9 @@
Esto controla por cuánto tiempo te advertirá el editor antes de autoguardar (en segundos..., 0 para desactivar)
Carpeta de Autoguardados
- Si está activado, el autoguardado se guardará en otra carpeta con su fecha en vez de sobreescribir el archivo actual. (song/autosaves/)
+ Si está activado, el autoguardado se guardará en otra carpeta con su fecha en vez de sobreescribir el archivo actual. (song/autosaves/)
+
+ Contador de Memoria Clásico
+ Si está activado, el contador de memoria mostrará el uso de memoria del GC de Haxe y su máximo (el comportamiento original) en vez de la memoria de trabajo vista en el Administrador de Tareas.
\ No newline at end of file
diff --git a/assets/languages/it/Options.xml b/assets/languages/it/Options.xml
index ed24a8ee31..42b9c1ce9e 100644
--- a/assets/languages/it/Options.xml
+++ b/assets/languages/it/Options.xml
@@ -199,5 +199,8 @@
Offset Editor Chart
Se abilitato, questo attiverà l'opzione Offset Canzone anche nel Editor Chart.
+
+ Contatore Memoria Classico
+ Se attivato, il contatore di memoria mostrerà l'uso di memoria del GC di Haxe e il suo picco (il comportamento originale) invece della memoria di lavoro vista nel Task Manager.
diff --git a/assets/languages/pl/Options.xml b/assets/languages/pl/Options.xml
index f14687f33f..9a518f35cd 100644
--- a/assets/languages/pl/Options.xml
+++ b/assets/languages/pl/Options.xml
@@ -175,6 +175,9 @@
Folder Autozapisów
Jeśli włączone, Edytor będzie zapisywać pliki w osobnym folderze, zamiast nadpisywania aktualnego pliku. (song/autosaves/)
+
+ Klasyczny Licznik Pamięci
+ Jeśli włączone, licznik pamięci pokaże użycie pamięci GC Haxe i jego szczyt (oryginalne zachowanie) zamiast pamięci roboczej widocznej w Menedżerze Zadań.
diff --git a/assets/languages/pt/Options.xml b/assets/languages/pt/Options.xml
index 82ce97c7d7..4b418925ec 100644
--- a/assets/languages/pt/Options.xml
+++ b/assets/languages/pt/Options.xml
@@ -206,6 +206,9 @@
Atraso no Mapeador
Se marcado, irá ativar o Atraso da Música no Editor de Mapas, também.
+
+ Contador de Memória Clássico
+ Se marcado, o contador de memória mostrará o uso de memória do GC de Haxe e o seu máximo (o comportamento original) em vez da memória de trabalho vista no Gerenciador de Tarefas.
\ No newline at end of file
diff --git a/source/funkin/backend/system/framerate/MemoryCounter.hx b/source/funkin/backend/system/framerate/MemoryCounter.hx
index 068399b512..39962e2399 100644
--- a/source/funkin/backend/system/framerate/MemoryCounter.hx
+++ b/source/funkin/backend/system/framerate/MemoryCounter.hx
@@ -28,14 +28,57 @@ class MemoryCounter extends Sprite {
addChild(label);
}
memoryPeakText.alpha = 0.5;
+ #if !(cpp && (windows || mac || linux))
+ memoryPeakText.visible = false;
+ #end
}
public function reload() {}
+ private var usingLegacy:Bool = false;
+
public override function __enterFrame(t:Int) {
if (alpha <= 0.05) return;
super.__enterFrame(t);
+ #if (cpp && (windows || mac || linux))
+ var legacy = funkin.options.Options.legacyMemoryCounter;
+
+ if (legacy) {
+ if (legacy != usingLegacy) {
+ usingLegacy = legacy;
+ memoryPeak = 0;
+ }
+
+ final mem = MemoryUtil.currentMemUsage();
+ if (memoryPeak < mem) memoryPeak = mem;
+ if (mem == memory) {
+ updateLabelPosition();
+ return;
+ }
+
+ memory = mem;
+ memoryPeakText.visible = true;
+ memoryText.text = CoolUtil.getSizeString(memory);
+ memoryPeakText.text = ' / ${CoolUtil.getSizeString(memoryPeak)}';
+ } else {
+ if (legacy != usingLegacy) usingLegacy = legacy;
+
+ final gcMem = MemoryUtil.currentMemUsage();
+ final osMem = MemoryUtil.currentProcessMemUsage();
+
+ if (gcMem == memory && osMem == memoryPeak) {
+ updateLabelPosition();
+ return;
+ }
+
+ memory = gcMem;
+ memoryPeak = osMem;
+ memoryPeakText.visible = true;
+ memoryText.text = CoolUtil.getSizeString(gcMem);
+ memoryPeakText.text = ' / ${CoolUtil.getSizeString(osMem)}';
+ }
+ #else
final mem = MemoryUtil.currentMemUsage();
if (mem == memory) {
@@ -44,9 +87,8 @@ class MemoryCounter extends Sprite {
}
memory = mem;
- if (memoryPeak < memory) memoryPeak = memory;
- memoryText.text = CoolUtil.getSizeString(memory);
- memoryPeakText.text = ' / ${CoolUtil.getSizeString(memoryPeak)}';
+ memoryText.text = CoolUtil.getSizeString(mem);
+ #end
updateLabelPosition();
}
diff --git a/source/funkin/backend/utils/MemoryUtil.hx b/source/funkin/backend/utils/MemoryUtil.hx
index 2de56184c1..87d75fdd15 100644
--- a/source/funkin/backend/utils/MemoryUtil.hx
+++ b/source/funkin/backend/utils/MemoryUtil.hx
@@ -119,6 +119,23 @@ final class MemoryUtil {
#end
}
+ /**
+ * Gets the current process memory usage (Working Set / RSS) from the OS.
+ * This is much more granular than Haxe GC memory and updates more frequently.
+ * Returns the value in bytes, matching what you see in Task Manager / Activity Monitor.
+ */
+ public static inline function currentProcessMemUsage():Float {
+ #if (cpp && windows)
+ return funkin.backend.utils.native.Windows.getCurrentProcessMemory();
+ #elseif (cpp && mac)
+ return funkin.backend.utils.native.Mac.getCurrentProcessMemory();
+ #elseif (cpp && linux)
+ return funkin.backend.utils.native.Linux.getCurrentProcessMemory();
+ #else
+ return currentMemUsage();
+ #end
+ }
+
/**
* Gets the memory type of the system.
diff --git a/source/funkin/backend/utils/native/Linux.hx b/source/funkin/backend/utils/native/Linux.hx
index 661c584267..001929d009 100644
--- a/source/funkin/backend/utils/native/Linux.hx
+++ b/source/funkin/backend/utils/native/Linux.hx
@@ -28,5 +28,25 @@ final class Linux {
{
return 0;
}
+
+ @:functionCode('
+ FILE *status = fopen("/proc/self/status", "r");
+ if (status == NULL) return 0.0;
+
+ char line[256];
+ while (fgets(line, sizeof(line), status)) {
+ long rss;
+ if (sscanf(line, "VmRSS: %ld kB", &rss) == 1) {
+ fclose(status);
+ return (double)(rss * 1024); // kB -> bytes
+ }
+ }
+ fclose(status);
+ return 0.0;
+ ')
+ public static function getCurrentProcessMemory():Float
+ {
+ return 0;
+ }
}
#end
\ No newline at end of file
diff --git a/source/funkin/backend/utils/native/Mac.hx b/source/funkin/backend/utils/native/Mac.hx
index afd9d58981..86924dc2eb 100644
--- a/source/funkin/backend/utils/native/Mac.hx
+++ b/source/funkin/backend/utils/native/Mac.hx
@@ -5,6 +5,7 @@ import funkin.backend.utils.NativeAPI.CodeCursor;
import openfl.ui.Mouse;
@:headerInclude('sys/sysctl.h')
+@:headerInclude('mach/mach.h')
@:dox(hide)
final class Mac
{
@@ -23,6 +24,19 @@ final class Mac
return 0;
}
+ @:functionCode('
+ task_basic_info_data_t info;
+ mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT;
+ if (task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &count) == KERN_SUCCESS) {
+ return (double)info.resident_size;
+ }
+ return 0.0;
+ ')
+ public static function getCurrentProcessMemory():Float
+ {
+ return 0;
+ }
+
public static function setMouseCursorIcon(icon:CodeCursor):Void
{
final valid:Bool = external.ExternalMac.setCursorIcon(icon.toInt(), null, 0, 0);
diff --git a/source/funkin/backend/utils/native/Windows.hx b/source/funkin/backend/utils/native/Windows.hx
index 545e34b62a..706eba21c2 100644
--- a/source/funkin/backend/utils/native/Windows.hx
+++ b/source/funkin/backend/utils/native/Windows.hx
@@ -27,6 +27,7 @@ import funkin.backend.utils.NativeAPI.MessageBoxIcon;
#include
#include
#include
+#include
#define SAFE_RELEASE(punk) \\
if ((punk) != NULL) \\
@@ -267,5 +268,17 @@ final class Windows {
{
return 0;
}
+
+ @:functionCode("
+ PROCESS_MEMORY_COUNTERS_EX pmc;
+ if (GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc))) {
+ return (double)pmc.WorkingSetSize;
+ }
+ return 0.0;
+ ")
+ public static function getCurrentProcessMemory():Float
+ {
+ return 0;
+ }
}
#end
\ No newline at end of file
diff --git a/source/funkin/options/Options.hx b/source/funkin/options/Options.hx
index b3984580fe..447b7d45cf 100644
--- a/source/funkin/options/Options.hx
+++ b/source/funkin/options/Options.hx
@@ -38,6 +38,7 @@ class Options
public static var devMode:Bool = false;
public static var betaUpdates:Bool = false;
public static var splashesEnabled:Bool = true;
+ public static var legacyMemoryCounter:Bool = false;
@:dox(hide) @:doNotSave public static var hitWindow:Float = 250; // DEPRECATED
public static var songOffset:Float = 0;
public static var framerate:Int = 120;
diff --git a/source/funkin/options/categories/DebugOptions.hx b/source/funkin/options/categories/DebugOptions.hx
index 4f63da38be..b1a0263270 100644
--- a/source/funkin/options/categories/DebugOptions.hx
+++ b/source/funkin/options/categories/DebugOptions.hx
@@ -20,5 +20,8 @@ class DebugOptions extends TreeMenuScreen {
add(new NumOption(getNameID("charterAutoSaveWarningTime"), getDescID("charterAutoSaveWarningTime"), 0, 15, 1, "charterAutoSaveWarningTime"));
add(new Checkbox(getNameID("charterAutoSavesSeparateFolder"), getDescID("charterAutoSavesSeparateFolder"), "charterAutoSavesSeparateFolder"));
add(new Checkbox(getNameID("songOffsetAffectEditors"), getDescID("songOffsetAffectEditors"), "songOffsetAffectEditors"));
+ #if (cpp && (windows || mac || linux))
+ add(new Checkbox(getNameID("legacyMemoryCounter"), getDescID("legacyMemoryCounter"), "legacyMemoryCounter"));
+ #end
}
}
\ No newline at end of file