Skip to content

Commit

Permalink
Added FpsIdlingMode
Browse files Browse the repository at this point in the history
  • Loading branch information
pthom committed Sep 30, 2024
1 parent 1c32050 commit b36b0b5
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 10 deletions.
61 changes: 61 additions & 0 deletions src/hello_imgui/doc_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,67 @@ the elements in the `RunnerParams` struct, or in the simpler `SimpleRunnerParam
__HelloImGui::GetRunnerParams()__ will return the runnerParams of the current application.


# Run Application while handling the rendering loop
If you want to be in control of the rendering loop, you may use the class `HelloImGui::Renderer` (available since September 2024)

```cpp

// HelloImGui::Renderer is an alternative to HelloImGui::Run, allowing fine-grained control over the rendering process.
// - It is customizable like HelloImGui::Run: construct it with `RunnerParams` or `SimpleRunnerParams`
// - `Render()` will render the application for one frame:
// Ensure that `Render()` is triggered regularly (e.g., through a loop or other mechanism) to maintain responsiveness.
// This method must be called on the main thread.
//
// A typical use case is:
// ```cpp
// HelloImGui::RunnerParams runnerParams;
// runnerParams.callbacks.ShowGui = ...; // your GUI function
// // Optionally, choose between Sleep, EarlyReturn, or Auto for fps idling mode:
// // runnerParams.fpsIdling.fpsIdlingMode = HelloImGui::FpsIdlingMode::Sleep; // or EarlyReturn, Auto
// Renderer renderer(runnerParams); // note: a distinct copy of the `RunnerParams` will be stored inside the HelloImGui::GetRunnerParams()
// while (! HelloImGui::GetRunnerParams()->appShallExit)
// {
// renderer.Render();
// }
// ```
//
// **Notes:**
// 1. Depending on the configuration (`runnerParams.fpsIdling.fpsIdlingMode`), `HelloImGui` may enter an idle state to
// reduce CPU usage, if no events are received (e.g., no input or interaction).
// In this case, `Render()` will either sleep or return immediately.
// By default,
// - On Emscripten, `Render()` will return immediately to avoid blocking the main thread.
// - On other platforms, it will sleep
// 2. Only one instance of `Renderer` can exist at a time.
// 3. If constructed with `RunnerParams`, a copy of the `RunnerParams` will be made (which you can access with `GetRunnerParams())`.
class Renderer
{
public:
// Initializes with the full customizable `RunnerParams` to set up the application.
// Nb: a distinct copy of the `RunnerParams` will be made, and you can access it with `GetRunnerParams()`.
Renderer(const RunnerParams& runnerParams);

// Initializes with SimpleRunnerParams.
Renderer(const SimpleRunnerParams& simpleParams);

// Initializes with a simple GUI function and additional parameters.
Renderer(
const VoidFunction &guiFunction,
const std::string &windowTitle = "",
bool windowSizeAuto = false,
bool windowRestorePreviousGeometry = false,
const ScreenSize &windowSize = DefaultWindowSize,
float fpsIdle = 10.f
);

// Render the current frame (or return immediately if in idle state).
void Render();

// Destructor (automatically tears down HelloImGui).
~Renderer();
};
```
----
# Place widgets in a DPI-aware way
Expand Down
7 changes: 7 additions & 0 deletions src/hello_imgui/doc_api.src.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ HelloImGui is extremely easy to use: there is **one** main function in the API,

@import "hello_imgui.h" {md_id=HelloImGui::Run}

# Run Application while handling the rendering loop
If you want to be in control of the rendering loop, you may use the class `HelloImGui::Renderer` (available since September 2024)

```cpp
@import "hello_imgui.h" {md_id=HelloImGui::Renderer}
```
----
# Place widgets in a DPI-aware way
Expand Down
20 changes: 20 additions & 0 deletions src/hello_imgui/doc_params.md
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,22 @@ See [runner_params.h](https://github.com/pthom/hello_imgui/blob/master/src/hello

```cpp

// FpsIdlingMode is an enum that describes the different modes of idling when rendering the GUI.
// - Sleep: the application will sleep when idling to reduce CPU usage.
// - EarlyReturn: rendering will return immediately when idling.
// This is specifically designed for event-driven, and real-time applications.
// Avoid using it in a tight loop without pauses, as it may cause excessive CPU consumption.
// - Auto: use platform-specific default behavior.
// On most platforms, it will sleep. On Emscripten, `Render()` will return immediately
// to avoid blocking the main thread.
// Note: you can override the default behavior by explicitly setting Sleep or EarlyReturn.
enum class FpsIdlingMode
{
Sleep,
EarlyReturn,
Auto,
};

// FpsIdling is a struct that contains Fps Idling parameters
struct FpsIdling
{
Expand Down Expand Up @@ -861,6 +877,10 @@ struct FpsIdling
// `rememberEnableIdling`: _bool, default=true_.
// If true, the last value of enableIdling is restored from the settings at startup.
bool rememberEnableIdling = false;

// `fpsIdlingMode`: _FpsIdlingMode, default=FpsIdlingMode::Automatic_.
// Sets the mode of idling when rendering the GUI (Sleep, EarlyReturn, Automatic)
FpsIdlingMode fpsIdlingMode = FpsIdlingMode::Auto;
};
```

Expand Down
15 changes: 10 additions & 5 deletions src/hello_imgui/hello_imgui.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ void Run(
//
// A typical use case is:
// ```cpp
// HelloImGui::RunnerParams runnerParams;
// runnerParams.callbacks.ShowGui = ...; // your GUI function
// // Optionally, choose between Sleep, EarlyReturn, or Auto for fps idling mode:
// // runnerParams.fpsIdling.fpsIdlingMode = HelloImGui::FpsIdlingMode::Sleep; // or EarlyReturn, Auto
// Renderer renderer(runnerParams); // note: a distinct copy of the `RunnerParams` will be stored inside the HelloImGui::GetRunnerParams()
// while (! HelloImGui::GetRunnerParams()->appShallExit)
// {
Expand All @@ -102,11 +106,12 @@ void Run(
// ```
//
// **Notes:**
// 1. Depending on the configuration (such as `fpsIdle`), `HelloImGui` may enter an idle state to reduce CPU usage,
// if no events are received (e.g., no input or interaction).
// In this case, `Render()` will either sleep or return immediately:
// - On Emscripten, `Render()` will return immediately to avoid blocking the main thread.
// - On other platforms, it will sleep
// 1. Depending on the configuration (`runnerParams.fpsIdling.fpsIdlingMode`), `HelloImGui` may enter an idle state to
// reduce CPU usage, if no events are received (e.g., no input or interaction).
// In this case, `Render()` will either sleep or return immediately.
// By default,
// - On Emscripten, `Render()` will return immediately to avoid blocking the main thread.
// - On other platforms, it will sleep
// 2. Only one instance of `Renderer` can exist at a time.
// 3. If constructed with `RunnerParams`, a copy of the `RunnerParams` will be made (which you can access with `GetRunnerParams())`.
class Renderer
Expand Down
17 changes: 12 additions & 5 deletions src/hello_imgui/internal/backend_impls/abstract_runner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1071,16 +1071,23 @@ void AbstractRunner::CreateFramesAndRender(bool insideReentrantCall)
params.fpsIdling.isIdling = shallIdle;
if (shallIdle)
{
bool idleByEarlyReturn_Emscripten = false;
#ifdef __EMSCRIPTEN__
idleByEarlyReturn_Emscripten = true;
#endif
bool idleByEarlyReturn = false;

if (idleByEarlyReturn_Emscripten)
if (params.fpsIdling.fpsIdlingMode == FpsIdlingMode::EarlyReturn)
idleByEarlyReturn = true;

if (params.fpsIdling.fpsIdlingMode == FpsIdlingMode::Auto)
{
// Under emscripten, the idling implementation is different:
// we cannot sleep (which would lead to a busy wait), so we skip rendering
// if the last frame was rendered in time for the desired FPS
#ifdef __EMSCRIPTEN__
idleByEarlyReturn = true;
#endif
}

if (idleByEarlyReturn)
{
if (fnWasLastFrameRenderedInTimeForDesiredFps())
return true;
}
Expand Down
20 changes: 20 additions & 0 deletions src/hello_imgui/runner_params.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,22 @@ std::string IniFolderLocation(IniFolderType iniFolderType);

// @@md#FpsIdling

// FpsIdlingMode is an enum that describes the different modes of idling when rendering the GUI.
// - Sleep: the application will sleep when idling to reduce CPU usage.
// - EarlyReturn: rendering will return immediately when idling.
// This is specifically designed for event-driven, and real-time applications.
// Avoid using it in a tight loop without pauses, as it may cause excessive CPU consumption.
// - Auto: use platform-specific default behavior.
// On most platforms, it will sleep. On Emscripten, `Render()` will return immediately
// to avoid blocking the main thread.
// Note: you can override the default behavior by explicitly setting Sleep or EarlyReturn.
enum class FpsIdlingMode
{
Sleep,
EarlyReturn,
Auto,
};

// FpsIdling is a struct that contains Fps Idling parameters
struct FpsIdling
{
Expand Down Expand Up @@ -137,6 +153,10 @@ struct FpsIdling
// `rememberEnableIdling`: _bool, default=true_.
// If true, the last value of enableIdling is restored from the settings at startup.
bool rememberEnableIdling = false;

// `fpsIdlingMode`: _FpsIdlingMode, default=FpsIdlingMode::Automatic_.
// Sets the mode of idling when rendering the GUI (Sleep, EarlyReturn, Automatic)
FpsIdlingMode fpsIdlingMode = FpsIdlingMode::Auto;
};
// @@md

Expand Down

0 comments on commit b36b0b5

Please sign in to comment.