Skip to content

Commit b31b84c

Browse files
committed
Qor idle modes, tick+fps decoupling, small fixes
1 parent 3e85498 commit b31b84c

11 files changed

+147
-21
lines changed

Qor/Input.h

+11-1
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,7 @@ class Input:
501501

502502
void gamepad_require_focus(bool b);
503503
void mouse_require_focus(bool b);
504-
504+
505505
private:
506506

507507
bool m_bRelMouse = false;
@@ -537,6 +537,13 @@ class Input:
537537
std::vector<SDL_Joystick*> m_Joysticks;
538538

539539
std::atomic<bool> m_bEscape = ATOMIC_VAR_INIT(false);
540+
541+
// triggers when an event needs to wake the Pipeline idle process
542+
boost::signals2::signal<void()> on_wakeup;
543+
544+
// The current event polling interval (usually 0).
545+
// Intended for use in Pipeline idle
546+
Freq::Time m_PollInterval;
540547
};
541548

542549
// Inherit from this to make interfaces to controllable objects
@@ -706,6 +713,9 @@ class Controller:
706713
//std::vector<std::string> m_BindNames;
707714
std::vector<std::weak_ptr<IInterface>> m_Interfaces;
708715

716+
//bool m_bIdle = false;
717+
//bool m_bDirty = false;
718+
709719
//boost::signals2::signal<void()>
710720
};
711721

Qor/LoadingState.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -115,12 +115,12 @@ LoadingState :: LoadingState(Qor* qor):
115115
//fade_to(Color::white(), m_FadeTime);
116116
m_Fade.frame(Frame<Color>(
117117
Color::white(),
118-
Freq::Time::seconds(0.5f),
118+
Freq::Time::seconds(0.25f),
119119
INTERPOLATE(out_sine<Color>)
120120
));
121121
//m_Fade.frame(Frame<Color>(
122122
// Color::white(), // wait a while
123-
// Freq::Time::seconds(1.0f),
123+
// Freq::Time::seconds(0.25f),
124124
// INTERPOLATE(Color, out_sine)
125125
//));
126126
#ifndef QOR_NO_AUDIO
@@ -207,7 +207,7 @@ void LoadingState :: logic(Freq::Time t)
207207
{
208208
m_Fade.frame(Frame<Color>(
209209
Color::black(),
210-
Freq::Time::seconds(0.5f),
210+
Freq::Time::seconds(0.25f),
211211
INTERPOLATE(out_sine<Color>)
212212
));
213213
}

Qor/Main.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ int main(int argc, char* argv[])
2121
Args args(argc, (const char**)argv);
2222

2323
auto engine = kit::make_unique<Qor>(args, Info::Program);
24+
25+
//engine->max_tick(300.0f);
26+
//engine->max_fps(30.0f);
2427

2528
if(engine->args().value_or("mod", "").empty())
2629
engine->states().register_class<BasicState>(); // run basic state

Qor/Pipeline.cpp

+17
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ Pipeline :: ~Pipeline()
9191

9292
void Pipeline :: backfaces(bool b)
9393
{
94+
auto l = this->lock();
9495
GL_TASK_START()
9596
if(b)
9697
glDisable(GL_CULL_FACE);
@@ -101,6 +102,13 @@ void Pipeline :: backfaces(bool b)
101102

102103
void Pipeline :: logic(Freq::Time t)
103104
{
105+
auto l = this->lock();
106+
if(m_Idle & IDLE_LOGIC){
107+
if(not m_bDirty)
108+
return;
109+
else
110+
m_bDirty = false;
111+
}
104112
m_pPartitioner->logic(t);
105113
}
106114

@@ -260,6 +268,13 @@ void Pipeline :: render(
260268
unsigned flags
261269
){
262270
auto l = this->lock();
271+
if(m_Idle & IDLE_RENDER){
272+
if(not m_bDirty)
273+
return;
274+
else
275+
m_bDirty = false;
276+
}
277+
263278
assert(m_pWindow);
264279
if(not partitioner)
265280
partitioner = m_pPartitioner.get();
@@ -268,6 +283,7 @@ void Pipeline :: render(
268283
return;
269284
if(!camera)
270285
return;
286+
271287
//if(!m_pRoot.lock())
272288
// return;
273289
//if(!m_pCamera.lock())
@@ -489,6 +505,7 @@ void Pipeline :: render(
489505

490506
void Pipeline :: winding(bool cw)
491507
{
508+
auto l = this->lock();
492509
GL_TASK_START()
493510
glFrontFace(cw ? GL_CW : GL_CCW);
494511
GL_TASK_END()

Qor/Pipeline.h

+30
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,33 @@ class Pipeline:
181181
void override_shader(PassType p, unsigned id);
182182
void clear_shader_overrides();
183183
std::shared_ptr<Program> shader();
184+
185+
enum IdleMode {
186+
NO_IDLE = 0,
187+
IDLE_LOGIC = kit::bit(0),
188+
IDLE_RENDER = kit::bit(1),
189+
IDLE = kit::bit(0) | kit::bit(1)
190+
};
191+
int idle() const {
192+
auto l = this->lock();
193+
return m_Idle;
194+
}
195+
void idle(int mode) {
196+
auto l = this->lock();
197+
m_Idle = mode;
198+
}
199+
bool dirty() const {
200+
auto l = this->lock();
201+
return m_bDirty;
202+
}
203+
void dirty(bool b) {
204+
auto l = this->lock();
205+
m_bDirty = b;
206+
}
207+
void redraw() {
208+
auto l = this->lock();
209+
m_bDirty = true;
210+
}
184211

185212
private:
186213

@@ -228,6 +255,9 @@ class Pipeline:
228255
const static std::vector<std::string> s_AttributeNames;
229256
#endif
230257

258+
int m_Idle = NO_IDLE;
259+
bool m_bDirty = false;
260+
231261
std::function<void()> m_BlendFunc;
232262
};
233263

Qor/Qor.cpp

+51-12
Original file line numberDiff line numberDiff line change
@@ -116,13 +116,15 @@ Qor :: Qor(const Args& args, std::string appname="qor"):
116116
#endif
117117

118118
m_pWindow = make_shared<Window>(m_Args, &m_Resources);
119+
m_MaxFPS = m_pWindow->refresh_rate();
119120

120121
//auto& renderer = CEGUI::OpenGLRenderer::bootstrapSystem();
121122
//CEGUI::OpenGLRenderer::create();
122123
//CEGUI::System::create(renderer);
123124

124125
m_pInput = make_shared<Input>(m_pWindow.get());
125126
m_pTimer = make_shared<Freq>();
127+
m_TPSAlarm.timer(m_pTimer->timeline());
126128
m_FPSAlarm.timer(m_pTimer->timeline());
127129
//m_pGUI = make_shared<GUI>(m_pTimer.get(), m_pWindow.get(), &m_Resources);
128130
//m_pGUI->init();
@@ -167,6 +169,7 @@ Qor :: Qor(const Args& args, std::string appname="qor"):
167169
//m_pCanvas = kit::make_unique<Canvas>(m_pWindow->size().x, m_pWindow->size().y);
168170
m_pPipeline = make_shared<Pipeline>(m_pWindow.get(), m_Args, &m_Resources);
169171

172+
m_TPSAlarm.set(Freq::Time::seconds(1.0f));
170173
m_FPSAlarm.set(Freq::Time::seconds(1.0f));
171174
}
172175

@@ -182,24 +185,38 @@ Qor :: ~Qor()
182185
void Qor :: logic()
183186
{
184187
Freq::Time t;
185-
if(m_FPSAlarm.elapsed()) {
186-
m_FPSAlarm.set(Freq::Time::seconds(1.0f));
187-
m_FPS = m_FramesLastSecond;
188-
LOGf("FPS: %s", m_FPS);
189-
m_FramesLastSecond = 0;
188+
if(m_TPSAlarm.elapsed()) {
189+
m_TPSAlarm.set(Freq::Time::seconds(1.0f));
190+
m_TPS = m_TicksLastSecond;
191+
LOGf("Ticks: %s", m_TPS);
192+
m_TicksLastSecond = 0;
190193
}
191-
while(!(t = m_pTimer->tick()).ui())
194+
m_TickAccum = 0;
195+
while(true)
192196
{
197+
// accumulated enough time to advance?
198+
t = m_pTimer->tick();
199+
m_TickAccum += t.s();
200+
m_FrameAccum += t.s();
201+
if(m_MaxTick < K_EPSILON) // MaxTick==0 for unlimited ticks
202+
break;
203+
if((m_TickAccum > 1.0f/m_MaxTick) ||
204+
(m_MaxFPS > K_EPSILON && m_FrameAccum > 1.0f/m_MaxFPS))
205+
break;
193206
try{
194207
this_thread::yield();
195208
}catch(...){
196209
quit();
197210
return;
198211
}
199212
}
200-
//t = m_pTimer->tick();
201-
++m_FramesLastSecond;
213+
//LOGf("%s", m_TickAccum);
214+
215+
++m_TicksLastSecond;
202216

217+
bool pipeline_dirty = m_pPipeline->dirty();
218+
int pipeline_idlemode = m_pPipeline->idle();
219+
203220
m_pInput->logic(t);
204221
if(m_pInput->quit_flag())
205222
{
@@ -208,17 +225,39 @@ void Qor :: logic()
208225
}
209226
//m_pAudio->logic(t.ms());
210227

228+
// Get pipeline idlemode and dirty state BEFORE logic() (since this changes)
229+
// Do not execute state logic if pipeline is using logic idle mode
211230
m_pPipeline->logic(t);
212-
if(state()){
213-
state()->logic(t);
214-
}
231+
if(not (pipeline_idlemode & Pipeline::IDLE_LOGIC) || pipeline_dirty)
232+
if(state()){
233+
state()->logic(t);
234+
}
215235
}
216236

217237
void Qor :: render()
218238
{
219239
if(Headless::enabled())
220240
return;
221-
241+
242+
bool pipeline_dirty = m_pPipeline->dirty();
243+
int pipeline_idlemode = m_pPipeline->idle();
244+
if((pipeline_idlemode & Pipeline::IDLE_RENDER) && not pipeline_dirty)
245+
return;
246+
247+
if(m_FPSAlarm.elapsed()) {
248+
m_FPSAlarm.set(Freq::Time::seconds(1.0f));
249+
m_FPS = m_FramesLastSecond;
250+
LOGf("FPS: %s", m_FPS);
251+
m_FramesLastSecond = 0;
252+
}
253+
254+
if(m_MaxFPS > K_EPSILON) // max fps limit?
255+
if(m_FrameAccum < 1.0f/m_MaxFPS) // not time for frame
256+
return; // do more logic() before render
257+
m_FrameAccum = 0;
258+
259+
++m_FramesLastSecond;
260+
222261
if(state())
223262
state()->render();
224263
m_pWindow->render();

Qor/Qor.h

+10
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,8 @@ class Qor:
210210
}
211211
void max_fps(float fps) {m_MaxFPS=fps;}
212212
float max_fps() const { return m_MaxFPS; }
213+
void max_tick(float tick) {m_MaxTick=tick;}
214+
float max_tick() const { return m_MaxTick; }
213215

214216
static Qor* get() { return s_pQor; } // try not to use this ;'(
215217

@@ -249,6 +251,7 @@ class Qor:
249251
std::atomic<bool> m_bQuit = ATOMIC_VAR_INIT(false);
250252

251253
float m_MaxFPS = 300.0f;
254+
float m_MaxTick = 300.0f;
252255

253256
// Engine components
254257
std::shared_ptr<Window> m_pWindow;
@@ -276,8 +279,15 @@ class Qor:
276279

277280
std::vector<std::string> m_SearchPaths;
278281

282+
float m_TickAccum = 0.0f;
283+
float m_FrameAccum = 0.0f;
284+
float m_TickDelay = 0.0f;
285+
286+
Freq::Alarm m_TPSAlarm;
279287
Freq::Alarm m_FPSAlarm;
288+
unsigned m_TicksLastSecond = 0;
280289
unsigned m_FramesLastSecond = 0;
290+
float m_TPS = 0.0f;
281291
float m_FPS = 0.0f;
282292
std::string m_App;
283293

Qor/Window.cpp

+15-1
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,13 @@ Window :: Window(
8686
if(video_cfg->has("anisotropy"))
8787
Texture::set_anisotropy(float(video_cfg->at<int>("anisotropy")));
8888

89-
if(video_cfg->at("vsync", false))
89+
if(video_cfg->at("vsync", false)){
9090
SDL_GL_SetSwapInterval(1);
91+
SDL_SetHintWithPriority(SDL_HINT_RENDER_VSYNC, "1", SDL_HINT_OVERRIDE);
92+
}else{
93+
SDL_GL_SetSwapInterval(0);
94+
SDL_SetHintWithPriority(SDL_HINT_RENDER_VSYNC, "0", SDL_HINT_OVERRIDE);
95+
}
9196

9297
m_pWindow = SDL_CreateWindow(
9398
m_Title.c_str(),
@@ -106,6 +111,15 @@ Window :: Window(
106111
//SDL_WINDOW_RESIZABLE
107112
);
108113

114+
SDL_DisplayMode current;
115+
for(int i = 0; i < SDL_GetNumVideoDisplays(); ++i){
116+
int r = SDL_GetCurrentDisplayMode(i, &current);
117+
if(r != 0)
118+
m_RefreshRate = std::max(current.refresh_rate, m_RefreshRate);
119+
}
120+
if(video_cfg->has("refreshrate"))
121+
m_RefreshRate = video_cfg->at<int>("refreshrate");
122+
109123
if(!m_pWindow)
110124
K_ERROR(GENERAL, SDL_GetError());
111125

Qor/Window.h

+2
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ class Window
6565

6666
boost::signals2::signal<void()> on_delay;
6767

68+
int refresh_rate() const { return m_RefreshRate; }
6869

6970
private:
7071

@@ -80,6 +81,7 @@ class Window
8081
mutable bool m_DelayReady = false;
8182
mutable bool m_DelayDone = false;
8283
mutable bool m_QuitFlag = false;
84+
int m_RefreshRate = 60;
8385
};
8486

8587
#endif

bin/settings.schema.json

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828
".name": "Vertical Sync",
2929
".desc": "Reduces tearing but may lower frame rate",
3030
".values": [ false, true ]
31+
},
32+
"refreshrate": {
33+
".name": "Refresh Rate",
34+
".desc": "Display refresh rate estimate"
3135
}
3236
},
3337

sg.json

+1-4
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@
55
}
66
},
77
"required": {
8-
"flipcoder/kit": {
9-
"link": "kit"
10-
},
118
"glew": "*",
129
"boost": "*",
1310
"openal": "*",
@@ -16,7 +13,7 @@
1613
"pangomm": "*",
1714
"libogg": "*",
1815
"libvorbis": "*",
19-
"devil": "*",
16+
"freeimage": "*",
2017
"g-truc/glm": "*",
2118
"rapidxml": "*",
2219
"jsoncpp": "*"

0 commit comments

Comments
 (0)