From 809ae20558529092694544bc615628d32f8a24cf Mon Sep 17 00:00:00 2001 From: Alug Date: Wed, 23 Oct 2024 02:37:08 +0200 Subject: [PATCH 1/8] use highly optmized (but slightly inaccurate) version of R_PointOnSide for rendering --- src/hardware/hw_main.c | 2 +- src/r_bsp.c | 3 ++- src/r_main.h | 6 ++++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 8c10f1eec..cfb9636d6 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -3103,7 +3103,7 @@ static void HWR_RenderBSPNode(INT32 bspnum) bsp = &nodes[bspnum]; // Decide which side the view point is on. - side = R_PointOnSide(viewx, viewy, bsp); + side = R_PointOnSideRender(viewx, viewy, bsp); // Recursively divide front space. if (HWR_PortalCheckBBox(bsp->bbox[side])) diff --git a/src/r_bsp.c b/src/r_bsp.c index 500a58035..a6530ce21 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.c @@ -1320,7 +1320,8 @@ void R_RenderBSPNode(INT32 bspnum) bsp = &nodes[bspnum]; // Decide which side the view point is on. - side = R_PointOnSide(viewx, viewy, bsp); + side = R_PointOnSideRender(viewx, viewy, bsp); + // Recursively divide front space. R_RenderBSPNode(bsp->children[side]); diff --git a/src/r_main.h b/src/r_main.h index cfca7e1a4..6b7c88de3 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -74,6 +74,12 @@ extern lighttable_t *zlight[LIGHTLEVELS][MAXLIGHTZ]; // Utility functions. INT32 R_PointOnSide(fixed_t x, fixed_t y, const node_t *node); +FUNCINLINE static ATTRINLINE PUREFUNC INT32 R_PointOnSideRender(fixed_t x, fixed_t y, const node_t *node) +{ + // use cross product to determine side quickly + return (INT64)(y - node->y) * node->dx - (INT64)(x - node->x) * node->dy > 0; +} + FUNCINLINE static ATTRINLINE PUREFUNC INT32 R_PointOnSegSide(fixed_t x, fixed_t y, const seg_t *line) { fixed_t lx = line->v1->x; -- 2.54.0 From e66d215dd309fb6c9892c80ee90035efb485d97c Mon Sep 17 00:00:00 2001 From: Alug Date: Wed, 20 Nov 2024 20:36:22 +0100 Subject: [PATCH 2/8] Fix integer overflows on very large numbers --- src/r_main.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/r_main.h b/src/r_main.h index 6b7c88de3..f173307b7 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -77,7 +77,7 @@ INT32 R_PointOnSide(fixed_t x, fixed_t y, const node_t *node); FUNCINLINE static ATTRINLINE PUREFUNC INT32 R_PointOnSideRender(fixed_t x, fixed_t y, const node_t *node) { // use cross product to determine side quickly - return (INT64)(y - node->y) * node->dx - (INT64)(x - node->x) * node->dy > 0; + return ((INT64)y - node->y) * node->dx - ((INT64)x - node->x) * node->dy > 0; } FUNCINLINE static ATTRINLINE PUREFUNC INT32 R_PointOnSegSide(fixed_t x, fixed_t y, const seg_t *line) @@ -88,7 +88,7 @@ FUNCINLINE static ATTRINLINE PUREFUNC INT32 R_PointOnSegSide(fixed_t x, fixed_t fixed_t ldy = line->v2->y - ly; // use cross product to determine side quickly - return (INT64)(y - ly) * ldx - (INT64)(x - lx) * ldy > 0; + return ((INT64)y - ly) * ldx - ((INT64)x - lx) * ldy > 0; } angle_t R_PointToAngle(fixed_t x, fixed_t y); -- 2.54.0 From a14c2f59b80eb404a5369b0a9419077b812afa74 Mon Sep 17 00:00:00 2001 From: Alug Date: Wed, 20 Nov 2024 21:25:18 +0100 Subject: [PATCH 3/8] rename to R_PointOnSideFast --- src/hardware/hw_main.c | 2 +- src/r_bsp.c | 2 +- src/r_main.h | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index cfb9636d6..45660af0b 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -3103,7 +3103,7 @@ static void HWR_RenderBSPNode(INT32 bspnum) bsp = &nodes[bspnum]; // Decide which side the view point is on. - side = R_PointOnSideRender(viewx, viewy, bsp); + side = R_PointOnSideFast(viewx, viewy, bsp); // Recursively divide front space. if (HWR_PortalCheckBBox(bsp->bbox[side])) diff --git a/src/r_bsp.c b/src/r_bsp.c index a6530ce21..a8e5b8551 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.c @@ -1320,7 +1320,7 @@ void R_RenderBSPNode(INT32 bspnum) bsp = &nodes[bspnum]; // Decide which side the view point is on. - side = R_PointOnSideRender(viewx, viewy, bsp); + side = R_PointOnSideFast(viewx, viewy, bsp); // Recursively divide front space. R_RenderBSPNode(bsp->children[side]); diff --git a/src/r_main.h b/src/r_main.h index f173307b7..d27530f41 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -74,7 +74,9 @@ extern lighttable_t *zlight[LIGHTLEVELS][MAXLIGHTZ]; // Utility functions. INT32 R_PointOnSide(fixed_t x, fixed_t y, const node_t *node); -FUNCINLINE static ATTRINLINE PUREFUNC INT32 R_PointOnSideRender(fixed_t x, fixed_t y, const node_t *node) +// This is not as accurate +// SHOULD NOT BE USED FOR ANYTHING GAMEPLAY RELATED!! +FUNCINLINE static ATTRINLINE PUREFUNC INT32 R_PointOnSideFast(fixed_t x, fixed_t y, const node_t *node) { // use cross product to determine side quickly return ((INT64)y - node->y) * node->dx - ((INT64)x - node->x) * node->dy > 0; -- 2.54.0 From bec632800de6dbca9476f7c193c906f746a5a5d6 Mon Sep 17 00:00:00 2001 From: Alug Date: Wed, 20 Nov 2024 21:26:18 +0100 Subject: [PATCH 4/8] use it for R_IsPointInSubsector this is fine since R_IsPointInSubsector is only used for precip spawn unless you disable noclipcam lol --- src/r_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/r_main.c b/src/r_main.c index 1c45d4112..c47095078 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -1076,7 +1076,8 @@ subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y) while (!(nodenum & NF_SUBSECTOR)) { node = &nodes[nodenum]; - side = R_PointOnSide(x, y, node); + //side = R_PointOnSide(x, y, node); + side = R_PointOnSideFast(x, y, node); // this is fine since R_IsPointInSubsector is only used for precip spawn unless you disable noclipcam lol nodenum = node->children[side]; } -- 2.54.0 From f499b1111393846ea11b9b01ed94a82e1caa491e Mon Sep 17 00:00:00 2001 From: Alug Date: Wed, 20 Nov 2024 21:27:29 +0100 Subject: [PATCH 5/8] add R_PointInSubsectorFast for non critical gameplay stuff like sounds and camera and some parts of rendering --- src/d_clisrv.c | 2 +- src/hardware/hw_main.c | 2 +- src/hardware/hw_portal.c | 2 +- src/p_mobj.c | 4 ++-- src/p_setup.c | 4 ++-- src/p_user.c | 4 ++-- src/r_fps.c | 2 +- src/r_main.h | 13 ++++++++++++- src/s_sound.c | 4 ++-- 9 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 6efeffc6f..f8f47f4ae 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2013,7 +2013,7 @@ static void CL_ReloadReceivedSavegame(void) for (i = 0; i < MAXSPLITSCREENPLAYERS; i++) { - camera[i].subsector = R_PointInSubsector(camera[i].x, camera[i].y); + camera[i].subsector = R_PointInSubsectorFast(camera[i].x, camera[i].y); } cl_redownloadinggamestate = false; diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 45660af0b..a0059f184 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -3177,7 +3177,7 @@ static gl_vissprite_t *HWR_NewVisSprite(void) // Finds a floor through which light does not pass. static fixed_t HWR_OpaqueFloorAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height) { - const sector_t *sec = R_PointInSubsector(x, y)->sector; + const sector_t *sec = R_PointInSubsectorFast(x, y)->sector; fixed_t floorz = sec->floorheight; if (sec->ffloors) diff --git a/src/hardware/hw_portal.c b/src/hardware/hw_portal.c index 96a1b300a..fb4d88cb3 100644 --- a/src/hardware/hw_portal.c +++ b/src/hardware/hw_portal.c @@ -132,7 +132,7 @@ void HWR_PortalFrame(gl_portal_t* portal) { portalclipline = NULL; portalcullsector = NULL; - viewsector = R_PointInSubsector(viewx, viewy)->sector; + viewsector = R_PointInSubsectorFast(viewx, viewy)->sector; } } diff --git a/src/p_mobj.c b/src/p_mobj.c index 9da7b0235..75746118e 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -3318,7 +3318,7 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled P_CheckCameraPosition(thiscam->x, thiscam->y, thiscam); - thiscam->subsector = R_PointInSubsector(thiscam->x, thiscam->y); + thiscam->subsector = R_PointInSubsectorFast(thiscam->x, thiscam->y); thiscam->floorz = tmfloorz; thiscam->ceilingz = tmceilingz; @@ -10368,7 +10368,7 @@ void P_PrecipitationEffects(void) for (y = yl; y <= yh; y += RADIUSSTEP) for (x = xl; x <= xh; x += RADIUSSTEP) { - if (R_PointInSubsector((fixed_t)x, (fixed_t)y)->sector->ceilingpic != skyflatnum) // Found the outdoors! + if (R_PointInSubsectorFast((fixed_t)x, (fixed_t)y)->sector->ceilingpic != skyflatnum) // Found the outdoors! continue; newdist = S_CalculateSoundDistance(players[displayplayers[0]].mo->x, players[displayplayers[0]].mo->y, 0, (fixed_t)x, (fixed_t)y, 0); diff --git a/src/p_setup.c b/src/p_setup.c index 93207a3c1..e304aa7f3 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2430,7 +2430,7 @@ static void P_SetupCamera(UINT8 pnum, camera_t *cam) cam->y = players[pnum].mo->y; cam->z = players[pnum].mo->z; cam->angle = players[pnum].mo->angle; - cam->subsector = R_PointInSubsector(cam->x, cam->y); // make sure camera has a subsector set -- Monster Iestyn (12/11/18) + cam->subsector = R_PointInSubsectorFast(cam->x, cam->y); // make sure camera has a subsector set -- Monster Iestyn (12/11/18) } else { @@ -2455,7 +2455,7 @@ static void P_SetupCamera(UINT8 pnum, camera_t *cam) cam->y = thing->y; cam->z = thing->z; cam->angle = FixedAngle((fixed_t)thing->angle << FRACBITS); - cam->subsector = R_PointInSubsector(cam->x, cam->y); // make sure camera has a subsector set -- Monster Iestyn (12/11/18) + cam->subsector = R_PointInSubsectorFast(cam->x, cam->y); // make sure camera has a subsector set -- Monster Iestyn (12/11/18) } } diff --git a/src/p_user.c b/src/p_user.c index 4041c17d6..2c061e7ce 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3357,7 +3357,7 @@ void P_DemoCameraMovement(camera_t *cam) democam.soundmobj = awayviewmobj_hack; // update subsector to avoid crashes; - cam->subsector = R_PointInSubsector(cam->x, cam->y); + cam->subsector = R_PointInSubsectorFast(cam->x, cam->y); } void P_ResetCamera(player_t *player, camera_t *thiscam) @@ -3398,7 +3398,7 @@ void P_ResetCamera(player_t *player, camera_t *thiscam) } thiscam->relativex = 0; - thiscam->subsector = R_PointInSubsector(thiscam->x,thiscam->y); + thiscam->subsector = R_PointInSubsectorFast(thiscam->x,thiscam->y); thiscam->radius = 20*FRACUNIT; thiscam->height = 16*FRACUNIT; diff --git a/src/r_fps.c b/src/r_fps.c index 0f86160a6..15c3f2259 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -193,7 +193,7 @@ void R_InterpolateView(fixed_t frac, boolean forceinvalid) viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT); viewplayer = newview->player; - viewsector = R_PointInSubsector(viewx, viewy)->sector; + viewsector = R_PointInSubsectorFast(viewx, viewy)->sector; R_SetupFreelook(); } diff --git a/src/r_main.h b/src/r_main.h index d27530f41..6d4546f39 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -102,10 +102,21 @@ fixed_t R_ScaleFromGlobalAngle(angle_t visangle); subsector_t *R_PointInSubsector(fixed_t x, fixed_t y); subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y); +// uses R_PointOnSideFast +// SHOULD NOT BE USED FOR ANYTHING GAMEPLAY RELATED!! +FUNCINLINE static ATTRINLINE subsector_t *R_PointInSubsectorFast(fixed_t x, fixed_t y) +{ + size_t nodenum = numnodes-1; + + while (!(nodenum & NF_SUBSECTOR)) + nodenum = nodes[nodenum].children[R_PointOnSideFast(x, y, nodes+nodenum)]; + + return &subsectors[nodenum & ~NF_SUBSECTOR]; +} + #define R_PointToDist(x, y) R_PointToDist2(viewx, viewy, x, y) #define R_PointToDist2(px2, py2, px1, py1) FixedHypot((px1) - (px2), (py1) - (py2)) - boolean R_DoCulling(line_t *cullheight, line_t *viewcullheight, fixed_t vz, fixed_t bottomh, fixed_t toph); void R_GetRenderBlockMapDimensions(fixed_t drawdist, INT32 *xl, INT32 *xh, INT32 *yl, INT32 *yh); diff --git a/src/s_sound.c b/src/s_sound.c index 868bccc77..d54ee2884 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -1046,7 +1046,7 @@ boolean S_AdjustSoundParams(const mobj_t *listener, const mobj_t *source, INT32 INT64 x, y, yl, yh, xl, xh; fixed_t newdist; - if (R_PointInSubsector(listensource.x, listensource.y)->sector->ceilingpic == skyflatnum) + if (R_PointInSubsectorFast(listensource.x, listensource.y)->sector->ceilingpic == skyflatnum) approx_dist = 0; else { @@ -1059,7 +1059,7 @@ boolean S_AdjustSoundParams(const mobj_t *listener, const mobj_t *source, INT32 for (y = yl; y <= yh; y += FRACUNIT*64) for (x = xl; x <= xh; x += FRACUNIT*64) { - if (R_PointInSubsector(x, y)->sector->ceilingpic == skyflatnum) + if (R_PointInSubsectorFast(x, y)->sector->ceilingpic == skyflatnum) { // Found the outdoors! newdist = S_CalculateSoundDistance(listensource.x, listensource.y, 0, x, y, 0); -- 2.54.0 From 5aff1acea895374bfc3a01861fba9bfa2b27ed3a Mon Sep 17 00:00:00 2001 From: Alug Date: Tue, 26 Nov 2024 19:18:34 +0100 Subject: [PATCH 6/8] mobjcache with explicit "true" check just in case smth throws a garbo value and is not actually a mobj thinker --- src/d_think.h | 1 + src/p_local.h | 1 + src/p_mobj.c | 31 ++++++++++++++++++++++++++++--- src/p_setup.c | 2 ++ src/p_tick.c | 27 +++++++++++++++++++++++++-- 5 files changed, 57 insertions(+), 5 deletions(-) diff --git a/src/d_think.h b/src/d_think.h index b907c17fd..6b8ee113a 100644 --- a/src/d_think.h +++ b/src/d_think.h @@ -49,6 +49,7 @@ typedef struct thinker_s // killough 11/98: count of how many other objects reference // this one using pointers. Used for garbage collection. INT32 references; + boolean cachable; } thinker_t; #endif diff --git a/src/p_local.h b/src/p_local.h index fe1d10d73..de90447bd 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -66,6 +66,7 @@ // both the head and tail of the thinker list extern thinker_t thinkercap; +extern mobj_t *mobjcache; void P_InitThinkers(void); void P_AddThinker(thinker_t *thinker); diff --git a/src/p_mobj.c b/src/p_mobj.c index 9da7b0235..937898ff6 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -48,6 +48,7 @@ actioncache_t actioncachehead; static mobj_t *overlaycap = NULL; static mobj_t *shadowcap = NULL; mobj_t *waypointcap = NULL; +mobj_t *mobjcache = NULL; void P_InitCachedActions(void) { @@ -9362,7 +9363,18 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) { const mobjinfo_t *info = &mobjinfo[type]; state_t *st; - mobj_t *mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL); + mobj_t *mobj; + + if (mobjcache != NULL) + { + mobj = mobjcache; + mobjcache = mobjcache->hnext; + memset(mobj, 0, sizeof(*mobj)); + } + else + { + mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL); + } // this is officially a mobj, declared as soon as possible. mobj->thinker.function.acp1 = (actionf_p1)P_MobjThinker; @@ -9823,7 +9835,18 @@ mobj_t *P_SpawnShadowMobj(mobj_t * caster) { const mobjinfo_t *info = &mobjinfo[MT_SHADOW]; state_t *st; - mobj_t *mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL); + mobj_t *mobj; + + if (mobjcache != NULL) + { + mobj = mobjcache; + mobjcache = mobjcache->hnext; + memset(mobj, 0, sizeof(*mobj)); + } + else + { + mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL); + } // this is officially a mobj, declared as soon as possible. mobj->thinker.function.acp1 = (actionf_p1)P_MobjThinker; @@ -10097,7 +10120,9 @@ void P_RemoveMobj(mobj_t *mobj) // Invalidate mobj_t data to cause crashes if accessed! memset(mobj, 0xff, sizeof(mobj_t)); #endif - Z_Free(mobj); // No refrences? Can be removed immediately! :D + // no references, dump it directly in the mobj cache + mobj->hnext = mobjcache; + mobjcache = mobj; } else { // Add thinker just to delay removing it until refrences are gone. diff --git a/src/p_setup.c b/src/p_setup.c index 93207a3c1..2d910aecb 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2753,6 +2753,8 @@ boolean P_SetupLevel(boolean skipprecip, boolean reloadinggamestate) R_ClearLevelSplats(); #endif + mobjcache = NULL; + R_InitializeLevelInterpolators(); P_InitThinkers(); diff --git a/src/p_tick.c b/src/p_tick.c index d6243fde9..119b1dce0 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -196,6 +196,8 @@ void P_AddThinker(thinker_t *thinker) thinkercap.prev = thinker; thinker->references = 0; // killough 11/98: init reference counter to 0 + + thinker->cachable = (thinker->function.acp1 == (actionf_p1)P_MobjThinker); } // @@ -235,7 +237,17 @@ void P_RemoveThinkerDelayed(thinker_t *thinker) * thinker->prev->next = thinker->next */ (next->prev = currentthinker = thinker->prev)->next = next; R_DestroyLevelInterpolators(thinker); - Z_Free(thinker); + + if (thinker->cachable == true) + { + // put cachable thinkers in the mobj cache, so we can avoid allocations + ((mobj_t *)thinker)->hnext = mobjcache; + mobjcache = (mobj_t *)thinker; + } + else + { + Z_Free(thinker); + } } // @@ -250,9 +262,20 @@ void P_UnlinkThinker(thinker_t *thinker) I_Assert(thinker->references == 0); (next->prev = thinker->prev)->next = next; - Z_Free(thinker); + + if (thinker->cachable == true) + { + // put cachable thinkers in the mobj cache, so we can avoid allocations + ((mobj_t *)thinker)->hnext = mobjcache; + mobjcache = (mobj_t *)thinker; + } + else + { + Z_Free(thinker); + } } + // // P_RemoveThinker // -- 2.54.0 From f973e6cd7299e5711f374cb705b5945105a983f4 Mon Sep 17 00:00:00 2001 From: Alug Date: Tue, 26 Nov 2024 18:21:10 +0100 Subject: [PATCH 7/8] init polyobj thinker cachable bool otherwise shit will die lol --- src/p_polyobj.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/p_polyobj.c b/src/p_polyobj.c index f890b0bd0..6f1259677 100644 --- a/src/p_polyobj.c +++ b/src/p_polyobj.c @@ -153,6 +153,9 @@ FUNCINLINE static ATTRINLINE void PolyObj_AddThinker(thinker_t *th) th->next = thinkercap.next; th->prev = &thinkercap; thinkercap.next = th; + + //th->references = 0; + th->cachable = false; // not initialising this made the mobjcache die thx! } static void FreeSideLists(void) -- 2.54.0 From 8662648ef5ff4ad7a42df7eb5e429641447788eb Mon Sep 17 00:00:00 2001 From: Alug Date: Tue, 26 Nov 2024 22:31:58 +0100 Subject: [PATCH 8/8] init polyobject thinker->references to 0 otherwise they wont get removed alot of the time --- src/p_polyobj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_polyobj.c b/src/p_polyobj.c index 6f1259677..ffc6651b8 100644 --- a/src/p_polyobj.c +++ b/src/p_polyobj.c @@ -154,7 +154,7 @@ FUNCINLINE static ATTRINLINE void PolyObj_AddThinker(thinker_t *th) th->prev = &thinkercap; thinkercap.next = th; - //th->references = 0; + th->references = 0; th->cachable = false; // not initialising this made the mobjcache die thx! } -- 2.54.0