Browse Source

ticker: replace linked lists wih dynamic arrays for entity groups.

undefined
Sam Hocevar 11 years ago
parent
commit
a65c0b7749
3 changed files with 85 additions and 64 deletions
  1. +9
    -2
      src/entity.cpp
  2. +22
    -1
      src/entity.h
  3. +54
    -61
      src/ticker.cpp

+ 9
- 2
src/entity.cpp View File

@@ -24,8 +24,7 @@ namespace lol
*/ */


Entity::Entity() : Entity::Entity() :
m_gamenext(0),
m_drawnext(0),
m_initstate(InitState::Ready),
m_ref(0), m_ref(0),
m_destroy(0) m_destroy(0)
{ {
@@ -50,6 +49,14 @@ char const *Entity::GetName()
return "<entity>"; return "<entity>";
} }


void Entity::InitGame()
{
}

void Entity::InitDraw()
{
}

void Entity::TickGame(float seconds) void Entity::TickGame(float seconds)
{ {
UNUSED(seconds); UNUSED(seconds);


+ 22
- 1
src/entity.h View File

@@ -24,6 +24,22 @@
namespace lol namespace lol
{ {


struct InitState
{
enum Value
{
Unknown,
Error,
NeedInitDraw,
NeedInitGame,
Ready,
}
m_value;

inline InitState(Value v) : m_value(v) {}
inline operator Value() { return m_value; }
};

class Entity class Entity
{ {
friend class Ticker; friend class Ticker;
@@ -40,6 +56,9 @@ protected:


inline int IsDestroying() { return m_destroy; } inline int IsDestroying() { return m_destroy; }


virtual void InitGame();
virtual void InitDraw();

virtual void TickGame(float seconds); virtual void TickGame(float seconds);
virtual void TickDraw(float seconds); virtual void TickDraw(float seconds);


@@ -76,6 +95,9 @@ protected:
static int const DRAWGROUP_BEGIN = GAMEGROUP_END; static int const DRAWGROUP_BEGIN = GAMEGROUP_END;
static int const ALLGROUP_END = DRAWGROUP_END; static int const ALLGROUP_END = DRAWGROUP_END;


/* The initialisation state */
InitState m_initstate;

#if !LOL_BUILD_RELEASE #if !LOL_BUILD_RELEASE
enum enum
{ {
@@ -102,7 +124,6 @@ private:
// Emcee end // Emcee end


private: private:
Entity *m_gamenext, *m_drawnext, *m_autonext;
int m_ref, m_autorelease, m_destroy; int m_ref, m_autorelease, m_destroy;
}; };




+ 54
- 61
src/ticker.cpp View File

@@ -30,7 +30,6 @@ static class TickerData


public: public:
TickerData() : TickerData() :
todolist(0), autolist(0),
nentities(0), nentities(0),
frame(0), recording(0), deltatime(0), bias(0), fps(0), frame(0), recording(0), deltatime(0), bias(0), fps(0),
#if LOL_BUILD_DEBUG #if LOL_BUILD_DEBUG
@@ -38,25 +37,15 @@ public:
#endif #endif
quit(0), quitframe(0), quitdelay(20), panic(0) quit(0), quitframe(0), quitdelay(20), panic(0)
{ {
for (int i = 0; i < Entity::ALLGROUP_END; i++)
list[i] = nullptr;
} }


~TickerData() ~TickerData()
{ {
ASSERT(nentities == 0, ASSERT(nentities == 0,
"still %i entities in ticker\n", nentities); "still %i entities in ticker\n", nentities);
#if !LOL_BUILD_RELEASE
if (autolist)
{
int count = 0;
for (Entity *e = autolist; e; e = e->m_autonext, count++)
;
ASSERT(count == 0, "still %i autoreleased entities\n", count);
}
#endif
Log::Debug("%i frames required to quit\n",
frame - quitframe);
ASSERT(m_autolist.Count() == 0,
"still %i autoreleased entities\n", m_autolist.Count());
Log::Debug("%i frames required to quit\n", frame - quitframe);


#if LOL_FEATURE_THREADS #if LOL_FEATURE_THREADS
gametick.Push(0); gametick.Push(0);
@@ -68,8 +57,8 @@ public:


private: private:
/* Entity management */ /* Entity management */
Entity *todolist, *autolist;
Entity *list[Entity::ALLGROUP_END];
Array<Entity *> m_todolist, m_autolist;
Array<Entity *> m_list[Entity::ALLGROUP_END];
int nentities; int nentities;


/* Fixed framerate management */ /* Fixed framerate management */
@@ -110,12 +99,11 @@ void Ticker::Register(Entity *entity)
/* If we are called from its constructor, the object's vtable is not /* If we are called from its constructor, the object's vtable is not
* ready yet, so we do not know which group this entity belongs to. Wait * ready yet, so we do not know which group this entity belongs to. Wait
* until the first tick. */ * until the first tick. */
entity->m_gamenext = data->todolist;
data->todolist = entity;
/* Objects are autoreleased by default. Put them in a circular list. */
data->m_todolist.Push(entity);

/* Objects are autoreleased by default. Put them in a list. */
data->m_autolist.Push(entity);
entity->m_autorelease = 1; entity->m_autorelease = 1;
entity->m_autonext = data->autolist;
data->autolist = entity;
entity->m_ref = 1; entity->m_ref = 1;


data->nentities++; data->nentities++;
@@ -131,14 +119,13 @@ void Ticker::Ref(Entity *entity)
if (entity->m_autorelease) if (entity->m_autorelease)
{ {
/* Get the entity out of the m_autorelease list. This is usually /* Get the entity out of the m_autorelease list. This is usually
* very fast since the first entry in autolist is the last
* very fast since the last entry in autolist is the last
* registered entity. */ * registered entity. */
for (Entity *e = data->autolist, *prev = nullptr; e;
prev = e, e = e->m_autonext)
for (int i = data->m_autolist.Count(); --i; )
{ {
if (e == entity)
if (data->m_autolist[i] == entity)
{ {
(prev ? prev->m_autonext : data->autolist) = e->m_autonext;
data->m_autolist.RemoveSwap(i);
break; break;
} }
} }
@@ -232,15 +219,15 @@ void TickerData::GameThreadTick()


#if 0 #if 0
Log::Debug("-------------------------------------\n"); Log::Debug("-------------------------------------\n");
for (int i = 0; i < Entity::ALLGROUP_END; i++)
for (int g = 0; g < Entity::ALLGROUP_END; ++g)
{ {
Log::Debug("%s Group %i\n", Log::Debug("%s Group %i\n",
(i < Entity::GAMEGROUP_END) ? "Game" : "Draw", i);
(g < Entity::GAMEGROUP_END) ? "Game" : "Draw", g);


for (Entity *e = data->list[i]; e; )
for (int i = 0; i < data->m_list[g].Count(); ++i)
{ {
Entity *e = data->m_list[g][i];
Log::Debug(" \\-- %s (m_ref %i, destroy %i)\n", e->GetName(), e->m_ref, e->m_destroy); Log::Debug(" \\-- %s (m_ref %i, destroy %i)\n", e->GetName(), e->m_ref, e->m_destroy);
e = (i < Entity::GAMEGROUP_END) ? e->m_gamenext : e->m_drawnext;
} }
} }
#endif #endif
@@ -286,8 +273,10 @@ void TickerData::GameThreadTick()
int n = 0; int n = 0;
data->panic = 2 * (data->panic + 1); 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->m_gamenext)
for (int g = 0; g < Entity::ALLGROUP_END && n < data->panic; ++g)
for (int i = 0; i < data->m_list[g].Count() && n < data->panic; ++i)
{
Entity * e = data->m_list[g][i];
if (e->m_ref) if (e->m_ref)
{ {
#if !LOL_BUILD_RELEASE #if !LOL_BUILD_RELEASE
@@ -296,6 +285,7 @@ void TickerData::GameThreadTick()
e->m_ref--; e->m_ref--;
n++; n++;
} }
}


#if !LOL_BUILD_RELEASE #if !LOL_BUILD_RELEASE
if (n) if (n)
@@ -309,53 +299,51 @@ void TickerData::GameThreadTick()
/* Garbage collect objects that can be destroyed. We can do this /* Garbage collect objects that can be destroyed. We can do this
* before inserting awaiting objects, because only objects already * before inserting awaiting objects, because only objects already
* inthe tick lists can be marked for destruction. */ * inthe tick lists can be marked for destruction. */
for (int i = 0; i < Entity::ALLGROUP_END; i++)
for (Entity *e = data->list[i], *prev = nullptr; e; )
for (int g = 0; g < Entity::ALLGROUP_END; ++g)
{
for (int i = 0; i < data->m_list[g].Count(); ++i)
{ {
if (e->m_destroy && i < Entity::GAMEGROUP_END)
Entity *e = data->m_list[g][i];

if (e->m_destroy && g < Entity::GAMEGROUP_END)
{ {
/* If entity is to be destroyed, remove it from the /* If entity is to be destroyed, remove it from the
* game tick list. */ * game tick list. */
(prev ? prev->m_gamenext : data->list[i]) = e->m_gamenext;

e = e->m_gamenext;
data->m_list[g].RemoveSwap(i);
} }
else if (e->m_destroy) else if (e->m_destroy)
{ {
/* If entity is to be destroyed, remove it from the /* If entity is to be destroyed, remove it from the
* draw tick list and destroy it. */ * draw tick list and destroy it. */
(prev ? prev->m_drawnext : data->list[i]) = e->m_drawnext;

Entity *tmp = e;
e = e->m_drawnext; /* Can only be in a draw group list */
delete tmp;
data->m_list[g].RemoveSwap(i);
delete e;


data->nentities--; data->nentities--;
} }
else else
{ {
if (e->m_ref <= 0 && i >= Entity::DRAWGROUP_BEGIN)
if (e->m_ref <= 0 && g >= Entity::DRAWGROUP_BEGIN)
e->m_destroy = 1; e->m_destroy = 1;
prev = e;
e = (i < Entity::GAMEGROUP_END) ? e->m_gamenext : e->m_drawnext;
} }
} }
}


/* Insert waiting objects into the appropriate lists */ /* Insert waiting objects into the appropriate lists */
while (data->todolist)
while (data->m_todolist.Count())
{ {
Entity *e = data->todolist;
data->todolist = e->m_gamenext;
Entity *e = data->m_todolist.Last();


e->m_gamenext = data->list[e->m_gamegroup];
data->list[e->m_gamegroup] = e;
e->m_drawnext = data->list[e->m_drawgroup];
data->list[e->m_drawgroup] = e;
data->m_todolist.Remove(-1);
data->m_list[e->m_gamegroup].Push(e);
data->m_list[e->m_drawgroup].Push(e);
} }


/* Tick objects for the game loop */ /* 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->m_gamenext)
for (int g = Entity::GAMEGROUP_BEGIN; g < Entity::GAMEGROUP_END; ++g)
for (int i = 0; i < data->m_list[g].Count(); ++i)
{
Entity *e = data->m_list[g][i];

if (!e->m_destroy) if (!e->m_destroy)
{ {
#if !LOL_BUILD_RELEASE #if !LOL_BUILD_RELEASE
@@ -372,6 +360,7 @@ void TickerData::GameThreadTick()
e->m_tickstate = Entity::STATE_IDLE; e->m_tickstate = Entity::STATE_IDLE;
#endif #endif
} }
}


Profiler::Stop(Profiler::STAT_TICK_GAME); Profiler::Stop(Profiler::STAT_TICK_GAME);
} }
@@ -381,9 +370,9 @@ void TickerData::DrawThreadTick()
Profiler::Start(Profiler::STAT_TICK_DRAW); Profiler::Start(Profiler::STAT_TICK_DRAW);


/* Tick objects for the draw loop */ /* Tick objects for the draw loop */
for (int i = Entity::DRAWGROUP_BEGIN; i < Entity::DRAWGROUP_END; i++)
for (int g = Entity::DRAWGROUP_BEGIN; g < Entity::DRAWGROUP_END; ++g)
{ {
switch (i)
switch (g)
{ {
case Entity::DRAWGROUP_BEGIN: case Entity::DRAWGROUP_BEGIN:
g_scene->Reset(); g_scene->Reset();
@@ -393,7 +382,10 @@ void TickerData::DrawThreadTick()
break; break;
} }


for (Entity *e = data->list[i]; e; e = e->m_drawnext)
for (int i = 0; i < data->m_list[g].Count(); ++i)
{
Entity *e = data->m_list[g][i];

if (!e->m_destroy) if (!e->m_destroy)
{ {
#if !LOL_BUILD_RELEASE #if !LOL_BUILD_RELEASE
@@ -410,6 +402,7 @@ void TickerData::DrawThreadTick()
e->m_tickstate = Entity::STATE_IDLE; e->m_tickstate = Entity::STATE_IDLE;
#endif #endif
} }
}


/* Do this render step */ /* Do this render step */
g_scene->Render(); g_scene->Render();
@@ -502,10 +495,10 @@ int Ticker::GetFrameNum()
void Ticker::Shutdown() void Ticker::Shutdown()
{ {
/* We're bailing out. Release all m_autorelease objects. */ /* We're bailing out. Release all m_autorelease objects. */
while (data->autolist)
while (data->m_autolist.Count())
{ {
data->autolist->m_ref--;
data->autolist = data->autolist->m_autonext;
data->m_autolist.Last()->m_ref--;
data->m_autolist.Remove(-1);
} }


data->quit = 1; data->quit = 1;


Loading…
Cancel
Save