Emscripten: Add "vsync" FPS limit mode
Would be really useful for native versions too, but it's more complicated to pull off. For now, vsync on native is the same as tpt.setfpscap(2).
This commit is contained in:
parent
9f71eb9d77
commit
c725894abd
@ -17,6 +17,7 @@ constexpr bool IGNORE_UPDATES = @IGNORE_UPDATES@;
|
|||||||
constexpr bool ENFORCE_HTTPS = @ENFORCE_HTTPS@;
|
constexpr bool ENFORCE_HTTPS = @ENFORCE_HTTPS@;
|
||||||
constexpr bool SECURE_CIPHERS_ONLY = @SECURE_CIPHERS_ONLY@;
|
constexpr bool SECURE_CIPHERS_ONLY = @SECURE_CIPHERS_ONLY@;
|
||||||
constexpr bool FFTW_PLAN_MEASURE = @FFTW_PLAN_MEASURE@;
|
constexpr bool FFTW_PLAN_MEASURE = @FFTW_PLAN_MEASURE@;
|
||||||
|
constexpr bool DEFAULT_VSYNC = @DEFAULT_VSYNC@;
|
||||||
constexpr char PATH_SEP_CHAR = '@PATH_SEP_CHAR@';
|
constexpr char PATH_SEP_CHAR = '@PATH_SEP_CHAR@';
|
||||||
|
|
||||||
constexpr char SERVER[] = "@SERVER@";
|
constexpr char SERVER[] = "@SERVER@";
|
||||||
|
14
src/FpsLimit.h
Normal file
14
src/FpsLimit.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
struct FpsLimitVsync
|
||||||
|
{
|
||||||
|
};
|
||||||
|
struct FpsLimitNone
|
||||||
|
{
|
||||||
|
};
|
||||||
|
struct FpsLimitExplicit
|
||||||
|
{
|
||||||
|
float value;
|
||||||
|
};
|
||||||
|
using FpsLimit = std::variant<FpsLimitVsync, FpsLimitNone, FpsLimitExplicit>;
|
@ -390,16 +390,17 @@ void EngineProcess()
|
|||||||
|
|
||||||
blit(engine.g->Data());
|
blit(engine.g->Data());
|
||||||
}
|
}
|
||||||
auto fpsLimit = ui::Engine::Ref().FpsLimit;
|
auto fpsLimit = ui::Engine::Ref().GetFpsLimit();
|
||||||
auto now = uint64_t(SDL_GetTicks()) * UINT64_C(1'000'000);
|
auto now = uint64_t(SDL_GetTicks()) * UINT64_C(1'000'000);
|
||||||
oldFrameStart = frameStart;
|
oldFrameStart = frameStart;
|
||||||
frameStart = now;
|
frameStart = now;
|
||||||
if (fpsLimit > 2)
|
if (auto *fpsLimitExplicit = std::get_if<FpsLimitExplicit>(&fpsLimit))
|
||||||
{
|
{
|
||||||
auto timeBlockDuration = uint64_t(UINT64_C(1'000'000'000) / fpsLimit);
|
auto timeBlockDuration = uint64_t(UINT64_C(1'000'000'000) / fpsLimitExplicit->value);
|
||||||
auto oldFrameStartTimeBlock = oldFrameStart / timeBlockDuration;
|
auto oldFrameStartTimeBlock = oldFrameStart / timeBlockDuration;
|
||||||
auto frameStartTimeBlock = oldFrameStartTimeBlock + 1U;
|
auto frameStartTimeBlock = oldFrameStartTimeBlock + 1U;
|
||||||
frameStart = std::max(frameStart, frameStartTimeBlock * timeBlockDuration);
|
frameStart = std::max(frameStart, frameStartTimeBlock * timeBlockDuration);
|
||||||
SDL_Delay((frameStart - now) / UINT64_C(1'000'000));
|
SDL_Delay((frameStart - now) / UINT64_C(1'000'000));
|
||||||
}
|
}
|
||||||
|
// TODO: else if (auto *fpsLimitExplicit = std::get_if<FpsLimitVsync>(&fpsLimit))
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "common/String.h"
|
#include "common/String.h"
|
||||||
#include "graphics/Pixel.h"
|
#include "graphics/Pixel.h"
|
||||||
|
#include "FpsLimit.h"
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
extern int desktopWidth;
|
extern int desktopWidth;
|
||||||
extern int desktopHeight;
|
extern int desktopHeight;
|
||||||
@ -40,6 +42,7 @@ void blit(pixel *vid);
|
|||||||
void SDLOpen();
|
void SDLOpen();
|
||||||
void SDLClose();
|
void SDLClose();
|
||||||
void SDLSetScreen(int scale_, bool resizable_, bool fullscreen_, bool altFullscreen_, bool forceIntegerScaling_);
|
void SDLSetScreen(int scale_, bool resizable_, bool fullscreen_, bool altFullscreen_, bool forceIntegerScaling_);
|
||||||
|
void SetFpsLimit(FpsLimit newFpsLimit);
|
||||||
bool RecreateWindow();
|
bool RecreateWindow();
|
||||||
void LoadWindowPosition();
|
void LoadWindowPosition();
|
||||||
void SaveWindowPosition();
|
void SaveWindowPosition();
|
||||||
|
@ -8,3 +8,7 @@ void MainLoop()
|
|||||||
EngineProcess();
|
EngineProcess();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetFpsLimit(FpsLimit newFpsLimit)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
@ -3,35 +3,33 @@
|
|||||||
#include <emscripten.h>
|
#include <emscripten.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
static float lastFpsLimit;
|
void SetFpsLimit(FpsLimit newFpsLimit)
|
||||||
static void updateFpsLimit()
|
|
||||||
{
|
{
|
||||||
lastFpsLimit = ui::Engine::Ref().FpsLimit;
|
static bool mainLoopSet = false;
|
||||||
if (lastFpsLimit == 60.0f) // TODO: rework FPS cap so 60.0 is not the default
|
if (!mainLoopSet)
|
||||||
|
{
|
||||||
|
emscripten_set_main_loop(EngineProcess, 0, 0);
|
||||||
|
mainLoopSet = true;
|
||||||
|
}
|
||||||
|
if (auto *fpsLimitVsync = std::get_if<FpsLimitVsync>(&newFpsLimit))
|
||||||
{
|
{
|
||||||
emscripten_set_main_loop_timing(EM_TIMING_RAF, 1);
|
emscripten_set_main_loop_timing(EM_TIMING_RAF, 1);
|
||||||
std::cerr << "implicit fps limit via vsync" << std::endl;
|
std::cerr << "implicit fps limit via vsync" << std::endl;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto delay = int(1000.f / lastFpsLimit);
|
auto delay = 0;
|
||||||
|
if (auto *fpsLimitExplicit = std::get_if<FpsLimitExplicit>(&newFpsLimit))
|
||||||
|
{
|
||||||
|
delay = int(1000.f / fpsLimitExplicit->value);
|
||||||
|
}
|
||||||
emscripten_set_main_loop_timing(EM_TIMING_SETTIMEOUT, delay);
|
emscripten_set_main_loop_timing(EM_TIMING_SETTIMEOUT, delay);
|
||||||
std::cerr << "explicit fps limit: " << delay << "ms delays" << std::endl;
|
std::cerr << "explicit fps limit: " << delay << "ms delays" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mainLoopBody()
|
|
||||||
{
|
|
||||||
EngineProcess();
|
|
||||||
if (lastFpsLimit != ui::Engine::Ref().FpsLimit)
|
|
||||||
{
|
|
||||||
updateFpsLimit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainLoop()
|
void MainLoop()
|
||||||
{
|
{
|
||||||
emscripten_set_main_loop(mainLoopBody, 0, 0);
|
SetFpsLimit(ui::Engine::Ref().GetFpsLimit());
|
||||||
updateFpsLimit();
|
EngineProcess();
|
||||||
mainLoopBody();
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "Engine.h"
|
#include "Engine.h"
|
||||||
|
#include "Config.h"
|
||||||
#include "PowderToySDL.h"
|
#include "PowderToySDL.h"
|
||||||
#include "Window.h"
|
#include "Window.h"
|
||||||
#include "common/platform/Platform.h"
|
#include "common/platform/Platform.h"
|
||||||
@ -10,7 +11,6 @@
|
|||||||
using namespace ui;
|
using namespace ui;
|
||||||
|
|
||||||
Engine::Engine():
|
Engine::Engine():
|
||||||
FpsLimit(60.0f),
|
|
||||||
drawingFrequencyLimit(0),
|
drawingFrequencyLimit(0),
|
||||||
Scale(1),
|
Scale(1),
|
||||||
Fullscreen(false),
|
Fullscreen(false),
|
||||||
@ -27,7 +27,15 @@ Engine::Engine():
|
|||||||
mousexp_(0),
|
mousexp_(0),
|
||||||
mouseyp_(0)
|
mouseyp_(0)
|
||||||
{
|
{
|
||||||
SetFps(FpsLimit); // populate dt with whatever that makes any sort of sense
|
SetFpsLimit(fpsLimit); // populate dt with whatever that makes any sort of sense
|
||||||
|
if constexpr (DEFAULT_VSYNC)
|
||||||
|
{
|
||||||
|
SetFpsLimit(FpsLimitVsync{});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetFpsLimit(FpsLimitExplicit{ 60.0f });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Engine::~Engine()
|
Engine::~Engine()
|
||||||
@ -41,6 +49,12 @@ Engine::~Engine()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Engine::SetFpsLimit(FpsLimit newFpsLimit)
|
||||||
|
{
|
||||||
|
fpsLimit = newFpsLimit;
|
||||||
|
::SetFpsLimit(fpsLimit);
|
||||||
|
}
|
||||||
|
|
||||||
void Engine::Begin()
|
void Engine::Begin()
|
||||||
{
|
{
|
||||||
//engine is now ready
|
//engine is now ready
|
||||||
@ -194,10 +208,14 @@ void Engine::Draw()
|
|||||||
void Engine::SetFps(float fps)
|
void Engine::SetFps(float fps)
|
||||||
{
|
{
|
||||||
this->fps = fps;
|
this->fps = fps;
|
||||||
if(FpsLimit > 2.0f)
|
if (std::holds_alternative<FpsLimitExplicit>(fpsLimit))
|
||||||
|
{
|
||||||
this->dt = 60/fps;
|
this->dt = 60/fps;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
this->dt = 1.0f;
|
this->dt = 1.0f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::onKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt)
|
void Engine::onKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt)
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "graphics/Pixel.h"
|
#include "graphics/Pixel.h"
|
||||||
#include "gui/interface/Point.h"
|
#include "gui/interface/Point.h"
|
||||||
#include <climits>
|
#include <climits>
|
||||||
|
#include "FpsLimit.h"
|
||||||
|
|
||||||
class Graphics;
|
class Graphics;
|
||||||
namespace ui
|
namespace ui
|
||||||
@ -76,7 +77,13 @@ namespace ui
|
|||||||
//void SetState(Window* state);
|
//void SetState(Window* state);
|
||||||
//inline State* GetState() { return state_; }
|
//inline State* GetState() { return state_; }
|
||||||
inline Window* GetWindow() { return state_; }
|
inline Window* GetWindow() { return state_; }
|
||||||
float FpsLimit;
|
|
||||||
|
void SetFpsLimit(FpsLimit newFpsLimit);
|
||||||
|
FpsLimit GetFpsLimit() const
|
||||||
|
{
|
||||||
|
return fpsLimit;
|
||||||
|
}
|
||||||
|
|
||||||
int drawingFrequencyLimit;
|
int drawingFrequencyLimit;
|
||||||
Graphics * g;
|
Graphics * g;
|
||||||
int Scale;
|
int Scale;
|
||||||
@ -85,6 +92,7 @@ namespace ui
|
|||||||
|
|
||||||
unsigned int FrameIndex;
|
unsigned int FrameIndex;
|
||||||
private:
|
private:
|
||||||
|
FpsLimit fpsLimit;
|
||||||
bool altFullscreen;
|
bool altFullscreen;
|
||||||
bool forceIntegerScaling = true;
|
bool forceIntegerScaling = true;
|
||||||
bool resizable;
|
bool resizable;
|
||||||
|
@ -1222,13 +1222,37 @@ int luatpt_setfpscap(lua_State* l)
|
|||||||
int acount = lua_gettop(l);
|
int acount = lua_gettop(l);
|
||||||
if (acount == 0)
|
if (acount == 0)
|
||||||
{
|
{
|
||||||
lua_pushnumber(l, ui::Engine::Ref().FpsLimit);
|
auto fpsLimit = ui::Engine::Ref().GetFpsLimit();
|
||||||
|
if (std::holds_alternative<FpsLimitVsync>(fpsLimit))
|
||||||
|
{
|
||||||
|
lua_pushliteral(l, "vsync");
|
||||||
|
}
|
||||||
|
else if (std::holds_alternative<FpsLimitNone>(fpsLimit))
|
||||||
|
{
|
||||||
|
lua_pushnumber(l, 2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lua_pushnumber(l, std::get<FpsLimitExplicit>(fpsLimit).value);
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
if (lua_isstring(l, 1) && byteStringEqualsLiteral(tpt_lua_toByteString(l, 1), "vsync"))
|
||||||
|
{
|
||||||
|
ui::Engine::Ref().SetFpsLimit(FpsLimitVsync{});
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
float fpscap = luaL_checknumber(l, 1);
|
float fpscap = luaL_checknumber(l, 1);
|
||||||
if (fpscap < 2)
|
if (fpscap < 2)
|
||||||
|
{
|
||||||
return luaL_error(l, "fps cap too small");
|
return luaL_error(l, "fps cap too small");
|
||||||
ui::Engine::Ref().FpsLimit = fpscap;
|
}
|
||||||
|
if (fpscap == 2)
|
||||||
|
{
|
||||||
|
ui::Engine::Ref().SetFpsLimit(FpsLimitNone{});
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ui::Engine::Ref().SetFpsLimit(FpsLimitExplicit{ fpscap });
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,10 +50,12 @@ if host_platform == 'emscripten'
|
|||||||
powder_files += files(
|
powder_files += files(
|
||||||
'PowderToySDLEmscripten.cpp',
|
'PowderToySDLEmscripten.cpp',
|
||||||
)
|
)
|
||||||
|
conf_data.set('DEFAULT_VSYNC', 'true')
|
||||||
else
|
else
|
||||||
powder_files += files(
|
powder_files += files(
|
||||||
'PowderToySDLCommon.cpp',
|
'PowderToySDLCommon.cpp',
|
||||||
)
|
)
|
||||||
|
conf_data.set('DEFAULT_VSYNC', 'false')
|
||||||
endif
|
endif
|
||||||
if is_x86
|
if is_x86
|
||||||
powder_files += files('X86KillDenormals.cpp')
|
powder_files += files('X86KillDenormals.cpp')
|
||||||
@ -66,6 +68,7 @@ render_files = files(
|
|||||||
font_files = files(
|
font_files = files(
|
||||||
'PowderToyFontEditor.cpp',
|
'PowderToyFontEditor.cpp',
|
||||||
'PowderToySDL.cpp',
|
'PowderToySDL.cpp',
|
||||||
|
'PowderToySDLCommon.cpp',
|
||||||
)
|
)
|
||||||
|
|
||||||
common_files = files(
|
common_files = files(
|
||||||
|
Reference in New Issue
Block a user