Merge branch 'optimize-precip-think' into 'master'

Optimize precipitation by eliminating the thinker entirely

See merge request KartKrew/Kart!1157
This commit is contained in:
Oni 2023-04-09 05:31:31 +00:00
commit d6d8cf548a
8 changed files with 84 additions and 52 deletions

View file

@ -5082,6 +5082,12 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
// uncapped/interpolation // uncapped/interpolation
interpmobjstate_t interp = {0}; interpmobjstate_t interp = {0};
// okay... this is a hack, but weather isn't networked, so it should be ok
if (!P_PrecipThinker(thing))
{
return;
}
// do interpolation // do interpolation
if (R_UsingFrameInterpolation() && !paused) if (R_UsingFrameInterpolation() && !paused)
{ {
@ -5181,13 +5187,6 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
vis->precip = true; vis->precip = true;
vis->bbox = false; vis->bbox = false;
// okay... this is a hack, but weather isn't networked, so it should be ok
if (!(thing->precipflags & PCF_THUNK))
{
P_PrecipThinker(thing);
thing->precipflags |= PCF_THUNK;
}
} }
#endif #endif

View file

@ -51,7 +51,7 @@ precise_t ps_playerthink_time = 0;
precise_t ps_botticcmd_time = 0; precise_t ps_botticcmd_time = 0;
precise_t ps_thinkertime = 0; precise_t ps_thinkertime = 0;
precise_t ps_thlist_times[NUM_THINKERLISTS]; precise_t ps_thlist_times[NUM_ACTIVETHINKERLISTS];
precise_t ps_acs_time = 0; precise_t ps_acs_time = 0;
int ps_checkposition_calls = 0; int ps_checkposition_calls = 0;
@ -367,7 +367,6 @@ static void M_DrawTickStats(void)
{"main ", "Main: ", &ps_thlist_times[THINK_MAIN]}, {"main ", "Main: ", &ps_thlist_times[THINK_MAIN]},
{"mobjs ", "Mobjs: ", &ps_thlist_times[THINK_MOBJ]}, {"mobjs ", "Mobjs: ", &ps_thlist_times[THINK_MOBJ]},
{"dynslop", "Dynamic slopes: ", &ps_thlist_times[THINK_DYNSLOPE]}, {"dynslop", "Dynamic slopes: ", &ps_thlist_times[THINK_DYNSLOPE]},
{"precip ", "Precipitation: ", &ps_thlist_times[THINK_PRECIP]},
{0} {0}
}; };

View file

@ -72,7 +72,13 @@ typedef enum
THINK_MAIN, THINK_MAIN,
THINK_MOBJ, THINK_MOBJ,
THINK_DYNSLOPE, THINK_DYNSLOPE,
THINK_PRECIP,
// Lists after this may exist but they do not call an
// action in P_RunThinkers
NUM_ACTIVETHINKERLISTS,
THINK_PRECIP = NUM_ACTIVETHINKERLISTS,
NUM_THINKERLISTS NUM_THINKERLISTS
} thinklistnum_t; /**< Thinker lists. */ } thinklistnum_t; /**< Thinker lists. */
extern thinker_t thlist[]; extern thinker_t thlist[];
@ -80,6 +86,7 @@ extern thinker_t thlist[];
void P_InitThinkers(void); void P_InitThinkers(void);
void P_AddThinker(const thinklistnum_t n, thinker_t *thinker); void P_AddThinker(const thinklistnum_t n, thinker_t *thinker);
void P_RemoveThinker(thinker_t *thinker); void P_RemoveThinker(thinker_t *thinker);
void P_UnlinkThinker(thinker_t *thinker);
// //
// P_USER // P_USER

View file

@ -546,7 +546,7 @@ static boolean P_SetPrecipMobjState(precipmobj_t *mobj, statenum_t state)
if (state == S_NULL) if (state == S_NULL)
{ // Remove mobj { // Remove mobj
P_RemovePrecipMobj(mobj); P_FreePrecipMobj(mobj);
return false; return false;
} }
st = &states[state]; st = &states[state];
@ -4174,25 +4174,33 @@ void P_RecalcPrecipInSector(sector_t *sector)
// //
// P_NullPrecipThinker // P_NullPrecipThinker
// //
// For "Blank" precipitation // Just the identification of a precip thinker. The thinker
// should never actually be called!
// //
void P_NullPrecipThinker(precipmobj_t *mobj) void P_NullPrecipThinker(precipmobj_t *mobj)
{ {
//(void)mobj; (void)mobj;
mobj->precipflags &= ~PCF_THUNK; I_Assert("P_NullPrecipThinker should not be called" == 0);
R_ResetPrecipitationMobjInterpolationState(mobj);
} }
void P_PrecipThinker(precipmobj_t *mobj) boolean P_PrecipThinker(precipmobj_t *mobj)
{ {
boolean flip = (mobj->precipflags & PCF_FLIP); boolean flip = (mobj->precipflags & PCF_FLIP);
if (mobj->lastThink == leveltime)
return true; // already thinked this tick
mobj->lastThink = leveltime;
R_ResetPrecipitationMobjInterpolationState(mobj);
P_CycleStateAnimation((mobj_t *)mobj); P_CycleStateAnimation((mobj_t *)mobj);
if (mobj->state == &states[S_RAINRETURN]) if (mobj->state == &states[S_RAINRETURN])
{ {
// Reset to ceiling! // Reset to ceiling!
P_SetPrecipMobjState(mobj, mobj->info->spawnstate); if (!P_SetPrecipMobjState(mobj, mobj->info->spawnstate))
return false;
mobj->z = (flip) ? (mobj->floorz) : (mobj->ceilingz); mobj->z = (flip) ? (mobj->floorz) : (mobj->ceilingz);
mobj->momz = FixedMul(-mobj->info->speed, mapobjectscale); mobj->momz = FixedMul(-mobj->info->speed, mapobjectscale);
mobj->precipflags &= ~PCF_SPLASH; mobj->precipflags &= ~PCF_SPLASH;
@ -4213,20 +4221,23 @@ void P_PrecipThinker(precipmobj_t *mobj)
// HACK: sprite changes are 1 tic late, so you would see splashes on the ceiling if not for this state. // HACK: sprite changes are 1 tic late, so you would see splashes on the ceiling if not for this state.
// We need to use the settings from the previous state, since some of those are NOT 1 tic late. // We need to use the settings from the previous state, since some of those are NOT 1 tic late.
INT32 frame = (mobj->frame & ~FF_FRAMEMASK); INT32 frame = (mobj->frame & ~FF_FRAMEMASK);
P_SetPrecipMobjState(mobj, S_RAINRETURN);
if (!P_SetPrecipMobjState(mobj, S_RAINRETURN))
return false;
mobj->frame = frame; mobj->frame = frame;
return; return true;
} }
else else
{ {
if (!P_SetPrecipMobjState(mobj, mobj->state->nextstate)) if (!P_SetPrecipMobjState(mobj, mobj->state->nextstate))
return; return false;
} }
} }
} }
if (mobj->precipflags & PCF_SPLASH) if (mobj->precipflags & PCF_SPLASH)
return; return true;
mobj->z += mobj->momz; mobj->z += mobj->momz;
@ -4240,12 +4251,16 @@ void P_PrecipThinker(precipmobj_t *mobj)
} }
else else
{ {
P_SetPrecipMobjState(mobj, mobj->info->deathstate); if (!P_SetPrecipMobjState(mobj, mobj->info->deathstate))
return false;
mobj->z = (flip) ? (mobj->ceilingz) : (mobj->floorz); mobj->z = (flip) ? (mobj->ceilingz) : (mobj->floorz);
mobj->precipflags |= PCF_SPLASH; mobj->precipflags |= PCF_SPLASH;
R_ResetPrecipitationMobjInterpolationState(mobj); R_ResetPrecipitationMobjInterpolationState(mobj);
} }
} }
return true;
} }
static void P_RingThinker(mobj_t *mobj) static void P_RingThinker(mobj_t *mobj)
@ -11253,7 +11268,7 @@ boolean P_MobjWasRemoved(mobj_t *mobj)
return true; return true;
} }
void P_RemovePrecipMobj(precipmobj_t *mobj) void P_FreePrecipMobj(precipmobj_t *mobj)
{ {
// unlink from sector and block lists // unlink from sector and block lists
P_UnsetPrecipThingPosition(mobj); P_UnsetPrecipThingPosition(mobj);
@ -11265,7 +11280,9 @@ void P_RemovePrecipMobj(precipmobj_t *mobj)
} }
// free block // free block
P_RemoveThinker((thinker_t *)mobj); // Precipmobjs don't actually think using their thinker,
// so the free cannot be delayed.
P_UnlinkThinker((thinker_t*)mobj);
} }
// Clearing out stuff for savegames // Clearing out stuff for savegames
@ -11301,12 +11318,7 @@ void P_RemoveSavegameMobj(mobj_t *mobj)
// free block // free block
// Here we use the same code as R_RemoveThinkerDelayed, but without reference counting (we're removing everything so it shouldn't matter) and without touching currentthinker since we aren't in P_RunThinkers // Here we use the same code as R_RemoveThinkerDelayed, but without reference counting (we're removing everything so it shouldn't matter) and without touching currentthinker since we aren't in P_RunThinkers
{ P_UnlinkThinker((thinker_t*)mobj);
thinker_t *thinker = (thinker_t *)mobj;
thinker_t *next = thinker->next;
(next->prev = thinker->prev)->next = next;
Z_Free(thinker);
}
} }
static CV_PossibleValue_t respawnitemtime_cons_t[] = {{1, "MIN"}, {300, "MAX"}, {0, NULL}}; static CV_PossibleValue_t respawnitemtime_cons_t[] = {{1, "MIN"}, {300, "MAX"}, {0, NULL}};

View file

@ -493,6 +493,8 @@ struct precipmobj_t
INT32 tics; // state tic counter INT32 tics; // state tic counter
state_t *state; state_t *state;
UINT32 flags; // flags from mobjinfo tables UINT32 flags; // flags from mobjinfo tables
tic_t lastThink;
}; };
struct actioncache_t struct actioncache_t
@ -540,9 +542,9 @@ void P_RemoveFloorSpriteSlope(mobj_t *mobj);
boolean P_BossTargetPlayer(mobj_t *actor, boolean closest); boolean P_BossTargetPlayer(mobj_t *actor, boolean closest);
boolean P_SupermanLook4Players(mobj_t *actor); boolean P_SupermanLook4Players(mobj_t *actor);
void P_DestroyRobots(void); void P_DestroyRobots(void);
void P_PrecipThinker(precipmobj_t *mobj); boolean P_PrecipThinker(precipmobj_t *mobj);
void P_NullPrecipThinker(precipmobj_t *mobj); void P_NullPrecipThinker(precipmobj_t *mobj);
void P_RemovePrecipMobj(precipmobj_t *mobj); void P_FreePrecipMobj(precipmobj_t *mobj);
void P_SetScale(mobj_t *mobj, fixed_t newscale); void P_SetScale(mobj_t *mobj, fixed_t newscale);
void P_XYMovement(mobj_t *mo); void P_XYMovement(mobj_t *mo);
void P_RingXYMovement(mobj_t *mo); void P_RingXYMovement(mobj_t *mo);

View file

@ -1833,16 +1833,18 @@ void P_SwitchWeather(preciptype_t newWeather)
if (purge == true) if (purge == true)
{ {
thinker_t *think; thinker_t *think;
thinker_t *next;
precipmobj_t *precipmobj; precipmobj_t *precipmobj;
for (think = thlist[THINK_PRECIP].next; think != &thlist[THINK_PRECIP]; think = think->next) for (think = thlist[THINK_PRECIP].next; think != &thlist[THINK_PRECIP]; think = next)
{ {
next = think->next;
if (think->function.acp1 != (actionf_p1)P_NullPrecipThinker) if (think->function.acp1 != (actionf_p1)P_NullPrecipThinker)
continue; // not a precipmobj thinker continue; // not a precipmobj thinker
precipmobj = (precipmobj_t *)think; precipmobj = (precipmobj_t *)think;
P_FreePrecipMobj(precipmobj);
P_RemovePrecipMobj(precipmobj);
} }
} }
else if (swap != MT_NULL) // Rather than respawn all that crap, reuse it! else if (swap != MT_NULL) // Rather than respawn all that crap, reuse it!

View file

@ -295,8 +295,6 @@ static thinker_t *currentthinker;
// //
void P_RemoveThinkerDelayed(thinker_t *thinker) void P_RemoveThinkerDelayed(thinker_t *thinker)
{ {
thinker_t *next;
if (thinker->references != 0) if (thinker->references != 0)
{ {
#ifdef PARANOIA #ifdef PARANOIA
@ -327,15 +325,30 @@ void P_RemoveThinkerDelayed(thinker_t *thinker)
return; return;
} }
/* Remove from main thinker list */ R_DestroyLevelInterpolators(thinker);
next = thinker->next;
/* Note that currentthinker is guaranteed to point to us, /* Note that currentthinker is guaranteed to point to us,
* and since we're freeing our memory, we had better change that. So * and since we're freeing our memory, we had better change that. So
* point it to thinker->prev, so the iterator will correctly move on to * point it to thinker->prev, so the iterator will correctly move on to
* thinker->prev->next = thinker->next */ * thinker->prev->next = thinker->next */
(next->prev = currentthinker = thinker->prev)->next = next; currentthinker = thinker->prev;
R_DestroyLevelInterpolators(thinker); /* Remove from main thinker list */
P_UnlinkThinker(thinker);
}
//
// P_UnlinkThinker()
//
// Actually removes thinker from the list and frees its memory.
//
void P_UnlinkThinker(thinker_t *thinker)
{
thinker_t *next = thinker->next;
I_Assert(thinker->references == 0);
(next->prev = thinker->prev)->next = next;
Z_Free(thinker); Z_Free(thinker);
} }
@ -437,7 +450,7 @@ static void P_RunThinkers(void)
{ {
size_t i; size_t i;
for (i = 0; i < NUM_THINKERLISTS; i++) for (i = 0; i < NUM_ACTIVETHINKERLISTS; i++)
{ {
ps_thlist_times[i] = I_GetPreciseTime(); ps_thlist_times[i] = I_GetPreciseTime();
for (currentthinker = thlist[i].next; currentthinker != &thlist[i]; currentthinker = currentthinker->next) for (currentthinker = thlist[i].next; currentthinker != &thlist[i]; currentthinker = currentthinker->next)

View file

@ -2465,6 +2465,12 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
// uncapped/interpolation // uncapped/interpolation
interpmobjstate_t interp = {0}; interpmobjstate_t interp = {0};
// okay... this is a hack, but weather isn't networked, so it should be ok
if (!P_PrecipThinker(thing))
{
return;
}
// do interpolation // do interpolation
if (R_UsingFrameInterpolation() && !paused) if (R_UsingFrameInterpolation() && !paused)
{ {
@ -2554,7 +2560,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
if (thing->subsector->sector->cullheight) if (thing->subsector->sector->cullheight)
{ {
if (R_DoCulling(thing->subsector->sector->cullheight, viewsector->cullheight, viewz, gz, gzt)) if (R_DoCulling(thing->subsector->sector->cullheight, viewsector->cullheight, viewz, gz, gzt))
goto weatherthink; return;
} }
// Determine the blendmode and translucency value // Determine the blendmode and translucency value
@ -2565,7 +2571,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
trans = (thing->frame & FF_TRANSMASK) >> FF_TRANSSHIFT; trans = (thing->frame & FF_TRANSMASK) >> FF_TRANSSHIFT;
if (trans >= NUMTRANSMAPS) if (trans >= NUMTRANSMAPS)
goto weatherthink; // cap return; // cap
} }
// store information in a vissprite // store information in a vissprite
@ -2623,14 +2629,6 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
// Fullbright // Fullbright
vis->colormap = colormaps; vis->colormap = colormaps;
weatherthink:
// okay... this is a hack, but weather isn't networked, so it should be ok
if (!(thing->precipflags & PCF_THUNK))
{
P_PrecipThinker(thing);
thing->precipflags |= PCF_THUNK;
}
} }
// R_AddSprites // R_AddSprites