Skip to content

Commit dde3f92

Browse files
committed
New power saver mode
1 parent 719c1b0 commit dde3f92

File tree

7 files changed

+103
-5
lines changed

7 files changed

+103
-5
lines changed

Config/Core/Renderer.yaml

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1-
vulkan: false # The Vulkan renderer is not yet implemented
2-
v-sync: false # To run or not to run in V-Sync mode
1+
vulkan: false # Enables Vulkan/WebGPU renderers
2+
v-sync: true # To run or not to run in V-Sync mode
33
msaa-samples: 8 # Multisampling sample count
4+
power-saving: # The power saving mode limits the number of frames that are drawn when idling. Will not work for applications with live plots or animations
5+
enabled: true
6+
idle-frames: 9 # The number of frames to output while idling

Framework/C/Interfaces/CRendererInterface.h

+3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ extern "C"
2020
UIMGUI_PUBLIC_API UImGui_String UImGui_Renderer_getGPUName();
2121
// Event Safety - begin, post-begin
2222
UIMGUI_PUBLIC_API UImGui_String UImGui_Renderer_getDriverVersion();
23+
24+
// Event Safety - begin, post-begin
25+
UIMGUI_PUBLIC_API void UImGui_Renderer_forceUpdate();
2326
#ifdef __cplusplus
2427
}
2528
#endif

Framework/C/Internal/RendererData.h

+7-3
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,19 @@ extern "C"
99
* @brief Renderer data struct
1010
* @var bVulkan - Whether the application uses the vulkan renderer
1111
* @var bUsingVSync - Whether the application uses VSync(sync the application framerate with monitor refresh rate)
12-
* @var msaaSamples - Number of samples for MSAA anti-aliasing
13-
* @var bSampleRateShading - Apply anti-aliasing on shaders
14-
* @var sampleRateShadingMult - Shader anti-aliasing multiplier
12+
* @var msaaSamples - Number of samples for MSAA antialiasing
13+
* @var bEnablePowerSavingMode - Whether to enable power saving(rendering with a reduce frame rate when the
14+
* application sits idle). Note: do not use for highly dynamic applications with plots or animations
15+
* @var idleFrameRate - The number of frames to render per second when idle
1516
*/
1617
typedef struct UIMGUI_PUBLIC_API UImGui_RendererData
1718
{
1819
bool bVulkan;
1920
bool bUsingVSync;
2021
uint32_t msaaSamples;
22+
23+
bool bEnablePowerSavingMode;
24+
float idleFrameRate;
2125
} UImGui_RendererData;
2226
#ifdef __cplusplus
2327
}

Framework/Core/Interfaces/RendererInterface.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,8 @@ const UImGui::FString& UImGui::Renderer::getDriverVersion() noexcept
3535
{
3636
return get().driverVersion;
3737
}
38+
39+
void UImGui::Renderer::forceUpdate() noexcept
40+
{
41+
get().bIdling = false;
42+
}

Framework/Core/Interfaces/RendererInterface.hpp

+4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ namespace UImGui
2020
static const FString& getGPUName() noexcept;
2121
// Event Safety - begin, post-begin
2222
static const FString& getDriverVersion() noexcept;
23+
24+
// Forces an update even when idling in power saving mode
25+
// Event Safety - begin, post-begin
26+
static void forceUpdate() noexcept;
2327
private:
2428
friend class RendererInternal;
2529
friend class WindowInternal;

Framework/Renderer/Renderer.cpp

+76
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,27 @@ void UImGui::RendererInternal::tick(void* rendererInstance) noexcept
5252
{
5353
auto& inst = *(static_cast<RendererInternal*>(rendererInstance));
5454
static double deltaTime = 0.0f;
55+
56+
#ifndef __EMSCRIPTEN__
57+
inst.bIdling = false;
58+
if (inst.data.idleFrameRate > 0.0f && inst.data.bEnablePowerSavingMode)
59+
{
60+
const double waitTimeout = 1.0 / inst.data.idleFrameRate;
61+
62+
Timer timer;
63+
timer.start();
64+
65+
glfwWaitEventsTimeout(waitTimeout);
66+
67+
timer.stop();
68+
const double elapsed = timer.get();
69+
const double duration = elapsed - waitTimeout;
70+
const double idleExpected = 1.0 / inst.data.idleFrameRate;
71+
72+
inst.bIdling = duration > (idleExpected * 0.9);
73+
}
74+
#endif
75+
5576
glfwPollEvents();
5677

5778
const double now = glfwGetTime();
@@ -61,6 +82,48 @@ void UImGui::RendererInternal::tick(void* rendererInstance) noexcept
6182
// Updates the state of the keybindings
6283
Global::get().window.updateKeyState();
6384

85+
#ifdef __EMSCRIPTEN__
86+
if (inst.data.idleFrameRate > 0.0f && inst.data.bEnablePowerSavingMode)
87+
{
88+
ImGuiContext& g = *ImGui::GetCurrentContext();
89+
bool bHasInputEvent = !g.InputEventsQueue.empty();
90+
91+
static double lastRefreshTime = 0.0f;
92+
static double accumulatedTime = 0.0f;
93+
accumulatedTime += deltaTime;
94+
95+
bool bShouldIdle = false;
96+
if (bHasInputEvent)
97+
{
98+
inst.bIdling = false;
99+
bShouldIdle = false;
100+
}
101+
else
102+
{
103+
inst.bIdling = true;
104+
if ((accumulatedTime - lastRefreshTime) < 1.0 / inst.data.idleFrameRate)
105+
bShouldIdle = true;
106+
else
107+
bShouldIdle = false;
108+
}
109+
110+
if (!bShouldIdle)
111+
{
112+
lastRefreshTime = accumulatedTime;
113+
accumulatedTime = 0.0f;
114+
}
115+
else
116+
{
117+
lastRefreshTime = 0.0f;
118+
return;
119+
}
120+
}
121+
#endif
122+
123+
// Do not render if the window is minimised
124+
if (Window::getWindowIconified())
125+
glfwWaitEvents();
126+
64127
inst.renderer->renderStart(deltaTime);
65128
GUIRenderer::beginUI(static_cast<float>(deltaTime), inst.renderer);
66129
inst.renderer->renderEnd(deltaTime);
@@ -90,6 +153,15 @@ void UImGui::RendererInternal::loadConfig() noexcept
90153
data.bUsingVSync = node["v-sync"].as<bool>();
91154
if (node["msaa-samples"])
92155
data.msaaSamples = node["msaa-samples"].as<uint32_t>();
156+
157+
const auto& powerSaving = node["power-saving"];
158+
if (powerSaving)
159+
{
160+
if (powerSaving["enabled"])
161+
data.bEnablePowerSavingMode = powerSaving["enabled"].as<bool>();
162+
if (powerSaving["idle-frames"])
163+
data.idleFrameRate = powerSaving["idle-frames"].as<float>();
164+
}
93165
}
94166

95167
void UImGui::RendererInternal::saveConfig() const noexcept
@@ -100,6 +172,10 @@ void UImGui::RendererInternal::saveConfig() const noexcept
100172
out << YAML::Key << "vulkan" << YAML::Value << data.bVulkan;
101173
out << YAML::Key << "v-sync" << YAML::Value << data.bUsingVSync;
102174
out << YAML::Key << "msaa-samples" << YAML::Value << data.msaaSamples;
175+
out << YAML::Key << "power-saving" << YAML::Value << YAML::BeginMap;
176+
out << YAML::Key << "enabled" << YAML::Value << data.bEnablePowerSavingMode;
177+
out << YAML::Key << "idle-frames" << YAML::Value << data.idleFrameRate;
178+
out << YAML::EndMap;
103179

104180
std::ofstream fout((Instance::get()->initInfo.configDir + "Core/Renderer.yaml").c_str());
105181
fout << out.c_str();

Framework/Renderer/Renderer.hpp

+3
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,10 @@ namespace UImGui
5353
.bVulkan = false,
5454
.bUsingVSync = true,
5555
.msaaSamples = 1,
56+
.bEnablePowerSavingMode = false,
57+
.idleFrameRate = 9.0f
5658
};
59+
bool bIdling = false;
5760
};
5861

5962
}

0 commit comments

Comments
 (0)