native: frame-rate setting, idle frame rate and battery power telemetry
- MtFrameRate setting (30 / 60 default / display max) as app.Get/SetFrameRateMode, with a "画面帧率" row injected into the system option dialog (mt_framerate); saved in the SDL pref path. - FrameRatePolicy in the live loop: 30 fps after 15 s without input (not while auto hunting), display switched to 60 Hz unless the highest mode, ADPF setPreferPowerEfficiency, vsync pacing when the display already runs at the target. --fps-mode / --idle-fps / --idle-after; --fps-cap / --refresh-rate still pin a test run. - Perf log: battery current/voltage/power, plugged, fps_mode, idle columns; perf_summary groups power by mode. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
c2cc093ed0
commit
82503315c6
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
// PORT: the player's frame-rate setting (system option dialog, app.Get/SetFrameRateMode), shared between
|
||||
// the script thread and the host's render loop (native_render/main.cpp), which paces frames by it and
|
||||
// saves it. 40250 has no counterpart: the PC client ran at the monitor's rate.
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace MtFrameRate {
|
||||
|
||||
enum EMode {
|
||||
MODE_SAVER = 0, // 30 fps
|
||||
MODE_STANDARD = 1, // 60 fps, 30 after a while without input
|
||||
MODE_HIGH = 2, // the display's highest rate (120 on current phones), 30 after a while without input
|
||||
MODE_COUNT
|
||||
};
|
||||
|
||||
inline std::atomic<int>& Mode()
|
||||
{
|
||||
static std::atomic<int> mode{MODE_STANDARD};
|
||||
return mode;
|
||||
}
|
||||
|
||||
inline int Get() { return Mode().load(std::memory_order_relaxed); }
|
||||
|
||||
inline void Set(int mode)
|
||||
{
|
||||
if (mode >= 0 && mode < MODE_COUNT)
|
||||
Mode().store(mode, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
} // namespace MtFrameRate
|
||||
@@ -0,0 +1,75 @@
|
||||
// The frame-rate row of the system option dialog (PORT; 40250 has no counterpart, the PC client ran at
|
||||
// the monitor's rate), run by PythonBoot::RunMainScript as module mt_framerate. It wraps
|
||||
// uiSystemOption.OptionDialog's __Load and fills the row the original layout leaves empty at y 210 (its
|
||||
// shadow slider is commented out), in the style of the fog buttons above it. The value is
|
||||
// app.Get/SetFrameRateMode (platform/EterBase/FrameRateMode.h); the host paces frames by it and saves it.
|
||||
// Strings are UTF-8 here and go through player.AutoHuntLocalize into the locale's code page.
|
||||
static const char c_szFrameRateOptionScript[] = R"PY(# -*- coding: utf-8 -*-
|
||||
import app
|
||||
import player
|
||||
import ui
|
||||
import uiSystemOption
|
||||
|
||||
L = player.AutoHuntLocalize
|
||||
|
||||
SMALL_BUTTON = "d:/ymir work/ui/public/small_button_%02d.sub"
|
||||
ROW_Y = 210
|
||||
MODE_TEXTS = ("30帧", "60帧", "最高")
|
||||
|
||||
|
||||
def _Refresh(buttons):
|
||||
mode = app.GetFrameRateMode()
|
||||
for i in xrange(len(buttons)):
|
||||
if i == mode:
|
||||
buttons[i].Down()
|
||||
else:
|
||||
buttons[i].SetUp()
|
||||
|
||||
|
||||
def _Select(buttons, mode):
|
||||
app.SetFrameRateMode(mode)
|
||||
_Refresh(buttons)
|
||||
|
||||
|
||||
def _Attach(dialog):
|
||||
board = dialog.GetChild("board")
|
||||
|
||||
label = ui.TextLine()
|
||||
label.SetParent(board)
|
||||
label.SetPosition(30, ROW_Y + 2)
|
||||
label.SetText(L("画面帧率"))
|
||||
label.Show()
|
||||
|
||||
buttons = []
|
||||
for i in xrange(len(MODE_TEXTS)):
|
||||
button = ui.RadioButton()
|
||||
button.SetParent(board)
|
||||
button.SetUpVisual(SMALL_BUTTON % 1)
|
||||
button.SetOverVisual(SMALL_BUTTON % 2)
|
||||
button.SetDownVisual(SMALL_BUTTON % 3)
|
||||
button.SetPosition(110 + 50 * i, ROW_Y)
|
||||
button.SetText(L(MODE_TEXTS[i]))
|
||||
button.SetEvent(lambda mode=i: _Select(buttons, mode))
|
||||
button.Show()
|
||||
buttons.append(button)
|
||||
_Refresh(buttons)
|
||||
|
||||
dialog.mtFrameRateLabel = label
|
||||
dialog.mtFrameRateButtons = buttons
|
||||
|
||||
|
||||
def __Install():
|
||||
load = uiSystemOption.OptionDialog._OptionDialog__Load
|
||||
|
||||
def Load(self):
|
||||
load(self)
|
||||
try:
|
||||
_Attach(self)
|
||||
except:
|
||||
import dbg
|
||||
dbg.TraceError("mt_framerate: cannot add the frame-rate row")
|
||||
|
||||
uiSystemOption.OptionDialog._OptionDialog__Load = Load
|
||||
|
||||
__Install()
|
||||
)PY";
|
||||
@@ -876,6 +876,7 @@ namespace PythonBoot
|
||||
// have to run once the root scripts are importable; a failure leaves the game without them, not broken.
|
||||
#include "AutoHuntScript.inc"
|
||||
#include "RegisterScript.inc"
|
||||
#include "FrameRateOptionScript.inc"
|
||||
|
||||
static void install_script_module(const char* c_szModule, const char* c_szScript)
|
||||
{
|
||||
@@ -931,6 +932,7 @@ bool RunMainScript(const char* lpCmdLine, std::string* error)
|
||||
{
|
||||
install_script_module("mt_autohunt", c_szAutoHuntScript);
|
||||
install_script_module("mt_register", c_szRegisterScript);
|
||||
install_script_module("mt_framerate", c_szFrameRateOptionScript);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "resource.h"
|
||||
#include "PythonApplication.h"
|
||||
#include "../EterLib/Camera.h"
|
||||
#include "../../platform/EterBase/FrameRateMode.h" // PORT: frame-rate setting
|
||||
|
||||
extern bool PERF_CHECKER_RENDER_GAME;
|
||||
extern D3DXCOLOR g_fSpecularColor;
|
||||
@@ -1191,6 +1192,21 @@ PyObject* appLogoClose(PyObject* poSelf, PyObject* poArgs)
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
// PORT: the frame-rate setting of the system option dialog (platform/EterBase/FrameRateMode.h).
|
||||
PyObject* appGetFrameRateMode(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
return Py_BuildValue("i", MtFrameRate::Get());
|
||||
}
|
||||
|
||||
PyObject* appSetFrameRateMode(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
int iMode;
|
||||
if (!PyTuple_GetInteger(poArgs, 0, &iMode))
|
||||
return Py_BuildException();
|
||||
MtFrameRate::Set(iMode);
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
void initapp()
|
||||
{
|
||||
static PyMethodDef s_methods[] =
|
||||
@@ -1257,6 +1273,8 @@ void initapp()
|
||||
{ "GetCursorPosition", appGetCursorPosition, METH_VARARGS },
|
||||
|
||||
{ "GetRandom", appGetRandom, METH_VARARGS },
|
||||
{ "GetFrameRateMode", appGetFrameRateMode, METH_VARARGS }, // PORT
|
||||
{ "SetFrameRateMode", appSetFrameRateMode, METH_VARARGS }, // PORT
|
||||
{ "RunPythonFile", appRunPythonFile, METH_VARARGS },
|
||||
{ "IsWebPageMode", appIsWebPageMode, METH_VARARGS },
|
||||
{ "ShowWebPage", appShowWebPage, METH_VARARGS },
|
||||
|
||||
Reference in New Issue
Block a user