From 0161879a845d0e0ed0ee721b93bc4051332f01ac Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Wed, 7 Dec 2011 01:06:19 +0000 Subject: [PATCH] core: try to merge Ticker and Emcee. Still not very good. --- src/Makefile.am | 2 +- src/application/application.cpp | 2 - src/core.h | 1 - src/eglapp.cpp | 5 - src/emcee.cpp | 82 --------- src/emcee.h | 41 ----- src/entity.cpp | 4 +- src/entity.h | 1 + src/platform/android/androidapp.cpp | 2 - src/platform/nacl/nacl_instance.cpp | 3 - src/platform/nacl/naclapp.cpp | 5 - src/platform/ps3/ps3app.cpp | 5 - src/platform/sdl/sdlapp.cpp | 4 - src/ticker.cpp | 269 +++++++++++++++++----------- src/ticker.h | 6 +- 15 files changed, 169 insertions(+), 263 deletions(-) delete mode 100644 src/emcee.cpp delete mode 100644 src/emcee.h diff --git a/src/Makefile.am b/src/Makefile.am index 9a9cedd2..38789e6b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -11,7 +11,7 @@ liblol_a_SOURCES = \ text.cpp text.h emitter.cpp emitter.h numeric.h hash.cpp hash.h \ worldentity.cpp worldentity.h gradient.cpp gradient.h half.cpp half.h \ platform.cpp platform.h sprite.cpp sprite.h trig.cpp trig.h \ - real.cpp real.h emcee.cpp emcee.h \ + real.cpp real.h \ \ lol/unit.h \ \ diff --git a/src/application/application.cpp b/src/application/application.cpp index 9afa2e55..cbb59346 100644 --- a/src/application/application.cpp +++ b/src/application/application.cpp @@ -59,7 +59,6 @@ class ApplicationData Application::Application(char const *name, ivec2 resolution, float framerate) { - Emcee::Setup(); data = new ApplicationData(name, resolution, framerate); } @@ -76,7 +75,6 @@ void Application::Run() Application::~Application() { delete data; - Emcee::Shutdown(); } } /* namespace lol */ diff --git a/src/core.h b/src/core.h index 5149d58b..4db4d973 100644 --- a/src/core.h +++ b/src/core.h @@ -103,7 +103,6 @@ static inline int isnan(float f) #include "application/application.h" // Managers -#include "emcee.h" #include "ticker.h" #include "forge.h" #include "tiler.h" diff --git a/src/eglapp.cpp b/src/eglapp.cpp index 20a40593..b5646309 100644 --- a/src/eglapp.cpp +++ b/src/eglapp.cpp @@ -158,16 +158,11 @@ void EglApp::Run() { while (!Ticker::Finished()) { - /* Tick the game */ - Ticker::TickGame(); - /* Tick the renderer, show the frame and clamp to desired framerate. */ Ticker::TickDraw(); #if defined USE_EGL eglSwapBuffers(data->egl_dpy, data->egl_surf); #endif - - Ticker::ClampFps(); } } diff --git a/src/emcee.cpp b/src/emcee.cpp deleted file mode 100644 index 0838291d..00000000 --- a/src/emcee.cpp +++ /dev/null @@ -1,82 +0,0 @@ -// -// Lol Engine -// -// Copyright: (c) 2010-2011 Sam Hocevar -// This program is free software; you can redistribute it and/or -// modify it under the terms of the Do What The Fuck You Want To -// Public License, Version 2, as published by Sam Hocevar. See -// http://sam.zoy.org/projects/COPYING.WTFPL for more details. -// - -#if defined HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include - -#include "core.h" - -namespace lol -{ - -/* - * Emcee implementation class - */ - -static Thread *GameThread, *DrawThread; - -static Queue gametick, drawtick; - -static void *GameThreadMain(void *data) -{ - while (!Ticker::Finished()) - for (;;) - { - int tick = gametick.Pop(); - if (!tick) - break; - - Ticker::TickGame(); - - drawtick.Push(1); - } - - drawtick.Push(0); -} - -static void *DrawThreadMain(void *data) -{ - for (;;) - { - int tick = drawtick.Pop(); - if (!tick) - break; - - Ticker::TickDraw(); - } -} - -void Emcee::Setup() -{ - GameThread = new Thread(GameThreadMain, NULL); - DrawThread = new Thread(DrawThreadMain, NULL); -} - -void Emcee::Shutdown() -{ -} - -void Emcee::SetState(Entity *entity, uint32_t state) -{ - -} - -void Emcee::SetStateWhenMatch(Entity *entity, uint32_t state, - Entity *other_entity, uint32_t other_state) -{ - -} - -} /* namespace lol */ - diff --git a/src/emcee.h b/src/emcee.h deleted file mode 100644 index 28b3c1bf..00000000 --- a/src/emcee.h +++ /dev/null @@ -1,41 +0,0 @@ -// -// Lol Engine -// -// Copyright: (c) 2010-2011 Sam Hocevar -// This program is free software; you can redistribute it and/or -// modify it under the terms of the Do What The Fuck You Want To -// Public License, Version 2, as published by Sam Hocevar. See -// http://sam.zoy.org/projects/COPYING.WTFPL for more details. -// - -// -// The Emcee class -// --------------- -// The Emcee manages tasks and their dependencies -// - -#if !defined __LOL_EMCEE_H__ -#define __LOL_EMCEE_H__ - -#include - -#include "entity.h" - -namespace lol -{ - -class Emcee -{ -public: - static void Setup(); - static void Shutdown(); - - static void SetState(Entity *entity, uint32_t state); - static void SetStateWhenMatch(Entity *entity, uint32_t state, - Entity *other_entity, uint32_t other_state); -}; - -} /* namespace lol */ - -#endif // __LOL_EMCEE_H__ - diff --git a/src/entity.cpp b/src/entity.cpp index 6ea9f071..bc1e8530 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -70,13 +70,13 @@ void Entity::TickDraw(float deltams) void Entity::SetState(uint32_t state) { - Emcee::SetState(this, state); + Ticker::SetState(this, state); } void Entity::SetStateWhenMatch(uint32_t state, Entity *other_entity, uint32_t other_state) { - Emcee::SetStateWhenMatch(this, state, other_entity, other_state); + Ticker::SetStateWhenMatch(this, state, other_entity, other_state); } } /* namespace lol */ diff --git a/src/entity.h b/src/entity.h index 0256a4eb..02ce1a20 100644 --- a/src/entity.h +++ b/src/entity.h @@ -29,6 +29,7 @@ class Entity friend class Ticker; friend class TickerData; friend class Dict; + friend class Emcee; protected: Entity(); diff --git a/src/platform/android/androidapp.cpp b/src/platform/android/androidapp.cpp index 3b81e1c1..5031592d 100644 --- a/src/platform/android/androidapp.cpp +++ b/src/platform/android/androidapp.cpp @@ -96,8 +96,6 @@ Java_org_zoy_LolEngine_LolView_nativeMove(JNIEnv* env, jobject thiz, extern "C" void Java_org_zoy_LolEngine_LolRenderer_nativeRender(JNIEnv* env) { - Ticker::ClampFps(); - Ticker::TickGame(); Ticker::TickDraw(); } diff --git a/src/platform/nacl/nacl_instance.cpp b/src/platform/nacl/nacl_instance.cpp index b26a69af..8a040425 100644 --- a/src/platform/nacl/nacl_instance.cpp +++ b/src/platform/nacl/nacl_instance.cpp @@ -126,9 +126,6 @@ void NaClInstance::DrawSelf() if (opengl_context_ == NULL) return; - Ticker::ClampFps(); - Ticker::TickGame(); - opengl_context_->MakeContextCurrent(this); Ticker::TickDraw(); opengl_context_->FlushContext(); diff --git a/src/platform/nacl/naclapp.cpp b/src/platform/nacl/naclapp.cpp index e7935b2e..1d1a9e63 100644 --- a/src/platform/nacl/naclapp.cpp +++ b/src/platform/nacl/naclapp.cpp @@ -58,16 +58,11 @@ void NaClApp::Run() { while (!Ticker::Finished()) { - /* Tick the game */ - Ticker::TickGame(); - /* Tick the renderer, show the frame and clamp to desired framerate. */ Ticker::TickDraw(); #if defined __native_client__ #endif - - Ticker::ClampFps(); } } diff --git a/src/platform/ps3/ps3app.cpp b/src/platform/ps3/ps3app.cpp index 0f6865cd..9a848425 100644 --- a/src/platform/ps3/ps3app.cpp +++ b/src/platform/ps3/ps3app.cpp @@ -118,9 +118,6 @@ void Ps3App::Run() { while (!Ticker::Finished()) { - /* Tick the game */ - Ticker::TickGame(); - /* Tick the renderer, show the frame and clamp to desired framerate. */ Ticker::TickDraw(); @@ -130,8 +127,6 @@ void Ps3App::Run() /* Check if exit callback was called */ cellSysutilCheckCallback(); #endif - - Ticker::ClampFps(); } } diff --git a/src/platform/sdl/sdlapp.cpp b/src/platform/sdl/sdlapp.cpp index 9e40cf34..2d04ca6a 100644 --- a/src/platform/sdl/sdlapp.cpp +++ b/src/platform/sdl/sdlapp.cpp @@ -84,15 +84,11 @@ void SdlApp::Run() { while (!Ticker::Finished()) { - /* Tick the game */ - Ticker::TickGame(); - /* Tick the renderer, show the frame and clamp to desired framerate. */ Ticker::TickDraw(); #if defined USE_SDL SDL_GL_SwapBuffers(); #endif - Ticker::ClampFps(); } } diff --git a/src/ticker.cpp b/src/ticker.cpp index b96e5b7e..0519eaf8 100644 --- a/src/ticker.cpp +++ b/src/ticker.cpp @@ -67,6 +67,12 @@ private: Timer timer; float deltams, bias, fps; + /* Background threads */ + static void *GameThreadMain(void *p); + static void *DrawThreadMain(void *p); /* unused */ + Thread *gamethread, *drawthread; + Queue gametick, drawtick; + /* Shutdown management */ int quit, quitframe, quitdelay, panic; } @@ -141,145 +147,188 @@ int Ticker::Unref(Entity *entity) return --entity->ref; } -void Ticker::Setup(float fps) +void *TickerData::GameThreadMain(void *p) { - data->fps = fps; -} + for (;;) + { + int tick = data->gametick.Pop(); + if (!tick) + break; -void Ticker::TickGame() -{ - Profiler::Stop(Profiler::STAT_TICK_FRAME); - Profiler::Start(Profiler::STAT_TICK_FRAME); + Profiler::Stop(Profiler::STAT_TICK_FRAME); + Profiler::Start(Profiler::STAT_TICK_FRAME); - Profiler::Start(Profiler::STAT_TICK_GAME); + Profiler::Start(Profiler::STAT_TICK_GAME); #if 0 - Log::Debug("-------------------------------------\n"); - for (int i = 0; i < Entity::ALLGROUP_END; i++) - { - Log::Debug("%s Group %i\n", - (i < Entity::GAMEGROUP_END) ? "Game" : "Draw", i); - - for (Entity *e = data->list[i]; e; ) + Log::Debug("-------------------------------------\n"); + for (int i = 0; i < Entity::ALLGROUP_END; i++) { - Log::Debug(" \\-- %s (ref %i, destroy %i)\n", e->GetName(), e->ref, e->destroy); - e = (i < Entity::GAMEGROUP_END) ? e->gamenext : e->drawnext; + Log::Debug("%s Group %i\n", + (i < Entity::GAMEGROUP_END) ? "Game" : "Draw", i); + + for (Entity *e = data->list[i]; e; ) + { + Log::Debug(" \\-- %s (ref %i, destroy %i)\n", e->GetName(), e->ref, e->destroy); + e = (i < Entity::GAMEGROUP_END) ? e->gamenext : e->drawnext; + } } - } #endif - data->frame++; + data->frame++; - /* If recording with fixed framerate, set deltams to a fixed value */ - if (data->recording && data->fps) - { - data->deltams = 1000.0f / data->fps; - } - else - { - data->deltams = data->timer.GetMs(); - data->bias += data->deltams; - } + /* If recording with fixed framerate, set deltams to a fixed value */ + if (data->recording && data->fps) + { + data->deltams = 1000.0f / data->fps; + } + else + { + data->deltams = data->timer.GetMs(); + data->bias += data->deltams; + } - /* If shutdown is stuck, kick the first entity we meet and see - * whether it makes things better. Note that it is always a bug to - * have referenced entities after 20 frames, but at least this - * safeguard makes it possible to exit the program cleanly. */ - if (data->quit && !((data->frame - data->quitframe) % data->quitdelay)) - { - int n = 0; - data->panic = 2 * (data->panic + 1); + /* If shutdown is stuck, kick the first entity we meet and see + * whether it makes things better. Note that it is always a bug to + * have referenced entities after 20 frames, but at least this + * safeguard makes it possible to exit the program cleanly. */ + if (data->quit && !((data->frame - data->quitframe) % data->quitdelay)) + { + int n = 0; + data->panic = 2 * (data->panic + 1); - for (int i = 0; i < Entity::ALLGROUP_END && n < data->panic; i++) - for (Entity *e = data->list[i]; e && n < data->panic; e = e->gamenext) - if (e->ref) - { + for (int i = 0; i < Entity::ALLGROUP_END && n < data->panic; i++) + for (Entity *e = data->list[i]; e && n < data->panic; e = e->gamenext) + if (e->ref) + { #if !LOL_RELEASE - Log::Error("poking %s\n", e->GetName()); + Log::Error("poking %s\n", e->GetName()); #endif - e->ref--; - n++; - } + e->ref--; + n++; + } #if !LOL_RELEASE - if (n) - Log::Error("%i entities stuck after %i frames, poked %i\n", - data->nentities, data->quitdelay, n); + if (n) + Log::Error("%i entities stuck after %i frames, poked %i\n", + data->nentities, data->quitdelay, n); #endif - data->quitdelay = data->quitdelay > 1 ? data->quitdelay / 2 : 1; - } + data->quitdelay = data->quitdelay > 1 ? data->quitdelay / 2 : 1; + } - /* Garbage collect objects that can be destroyed. We can do this - * before inserting awaiting objects, because only objects already in - * the tick lists can be marked for destruction. */ - for (int i = 0; i < Entity::ALLGROUP_END; i++) - for (Entity *e = data->list[i], *prev = NULL; e; ) - { - if (e->destroy && i < Entity::GAMEGROUP_END) + /* Garbage collect objects that can be destroyed. We can do this + * before inserting awaiting objects, because only objects already + * inthe tick lists can be marked for destruction. */ + for (int i = 0; i < Entity::ALLGROUP_END; i++) + for (Entity *e = data->list[i], *prev = NULL; e; ) { - /* If entity is to be destroyed, remove it from the - * game tick list. */ - (prev ? prev->gamenext : data->list[i]) = e->gamenext; - - e = e->gamenext; + if (e->destroy && i < Entity::GAMEGROUP_END) + { + /* If entity is to be destroyed, remove it from the + * game tick list. */ + (prev ? prev->gamenext : data->list[i]) = e->gamenext; + + e = e->gamenext; + } + else if (e->destroy) + { + /* If entity is to be destroyed, remove it from the + * draw tick list and destroy it. */ + (prev ? prev->drawnext : data->list[i]) = e->drawnext; + + Entity *tmp = e; + e = e->drawnext; /* Can only be in a draw group list */ + delete tmp; + + data->nentities--; + } + else + { + if (e->ref <= 0 && i >= Entity::DRAWGROUP_BEGIN) + e->destroy = 1; + prev = e; + e = (i < Entity::GAMEGROUP_END) ? e->gamenext : e->drawnext; + } } - else if (e->destroy) - { - /* If entity is to be destroyed, remove it from the - * draw tick list and destroy it. */ - (prev ? prev->drawnext : data->list[i]) = e->drawnext; - Entity *tmp = e; - e = e->drawnext; /* Can only be in a draw group list */ - delete tmp; + /* Insert waiting objects into the appropriate lists */ + while (data->todolist) + { + Entity *e = data->todolist; + data->todolist = e->gamenext; - data->nentities--; - } - else - { - if (e->ref <= 0 && i >= Entity::DRAWGROUP_BEGIN) - e->destroy = 1; - prev = e; - e = (i < Entity::GAMEGROUP_END) ? e->gamenext : e->drawnext; - } + e->gamenext = data->list[e->gamegroup]; + data->list[e->gamegroup] = e; + e->drawnext = data->list[e->drawgroup]; + data->list[e->drawgroup] = e; } - /* Insert waiting objects into the appropriate lists */ - while (data->todolist) - { - Entity *e = data->todolist; - data->todolist = e->gamenext; - - e->gamenext = data->list[e->gamegroup]; - data->list[e->gamegroup] = e; - e->drawnext = data->list[e->drawgroup]; - data->list[e->drawgroup] = e; - } - - /* Tick objects for the game loop */ - for (int i = Entity::GAMEGROUP_BEGIN; i < Entity::GAMEGROUP_END; i++) - for (Entity *e = data->list[i]; e; e = e->gamenext) - if (!e->destroy) - { + /* Tick objects for the game loop */ + for (int i = Entity::GAMEGROUP_BEGIN; i < Entity::GAMEGROUP_END; i++) + for (Entity *e = data->list[i]; e; e = e->gamenext) + if (!e->destroy) + { #if !LOL_RELEASE - if (e->state != Entity::STATE_IDLE) - Log::Error("entity not idle for game tick\n"); - e->state = Entity::STATE_PRETICK_GAME; + if (e->state != Entity::STATE_IDLE) + Log::Error("entity not idle for game tick\n"); + e->state = Entity::STATE_PRETICK_GAME; #endif - e->TickGame(data->deltams); + e->TickGame(data->deltams); #if !LOL_RELEASE - if (e->state != Entity::STATE_POSTTICK_GAME) - Log::Error("entity missed super game tick\n"); - e->state = Entity::STATE_IDLE; + if (e->state != Entity::STATE_POSTTICK_GAME) + Log::Error("entity missed super game tick\n"); + e->state = Entity::STATE_IDLE; #endif - } + } + + Profiler::Stop(Profiler::STAT_TICK_GAME); + + data->drawtick.Push(1); + } + + data->drawtick.Push(0); + + return NULL; +} + +void *TickerData::DrawThreadMain(void *p) +{ + for (;;) + { + int tick = data->drawtick.Pop(); + if (!tick) + break; + + data->gametick.Push(1); + } - Profiler::Stop(Profiler::STAT_TICK_GAME); + return NULL; +} + +void Ticker::SetState(Entity *entity, uint32_t state) +{ + +} + +void Ticker::SetStateWhenMatch(Entity *entity, uint32_t state, + Entity *other_entity, uint32_t other_state) +{ + +} + +void Ticker::Setup(float fps) +{ + data->fps = fps; + + data->gamethread = new Thread(TickerData::GameThreadMain, NULL); + data->gametick.Push(1); } void Ticker::TickDraw() { + data->drawtick.Pop(); + Profiler::Start(Profiler::STAT_TICK_DRAW); Video::Clear(); @@ -322,10 +371,11 @@ void Ticker::TickDraw() Profiler::Stop(Profiler::STAT_TICK_DRAW); Profiler::Start(Profiler::STAT_TICK_BLIT); -} -void Ticker::ClampFps() -{ + /* Signal game thread that it can carry on */ + data->gametick.Push(1); + + /* Clamp FPS */ Profiler::Stop(Profiler::STAT_TICK_BLIT); /* If framerate is fixed, force wait time to 1/FPS. Otherwise, set wait @@ -368,6 +418,9 @@ void Ticker::Shutdown() data->quit = 1; data->quitframe = data->frame; + + data->gametick.Push(0); + delete data->gamethread; } int Ticker::Finished() diff --git a/src/ticker.h b/src/ticker.h index 7811d502..6da27fb0 100644 --- a/src/ticker.h +++ b/src/ticker.h @@ -32,15 +32,17 @@ public: static int Unref(Entity *entity); static void Setup(float fps); - static void TickGame(); static void TickDraw(); - static void ClampFps(); static void StartBenchmark(); static void StopBenchmark(); static void StartRecording(); static void StopRecording(); static int GetFrameNum(); + static void SetState(Entity *entity, uint32_t state); + static void SetStateWhenMatch(Entity *entity, uint32_t state, + Entity *other_entity, uint32_t other_state); + static void Shutdown(); static int Finished(); };