- Same as last ZDBSP change: Do not count the segs in a separate pass in CreateNode().

With this, I can't think of any other simplifications I can make to speed up polyobject
  splitting.

  In my totally unscientific timedemo test, using the nodebuilder to sort polyobjects
  inside their subsectors amounted to just 0.1 ms longer per frame (a difference of 321.3 vs
  334.9 fps). I think that's acceptable. (For comparison, the unsimplified nodebuilder was
  about 0.05 ms slower per frame, or 315.8 vs 334.9 fps. Is that considered a 33% speedup?)

SVN r2479 (polyobjects)
This commit is contained in:
Randy Heit 2010-07-31 04:53:49 +00:00
parent edb4686a48
commit 537105b8cd
2 changed files with 25 additions and 27 deletions

View file

@ -124,35 +124,38 @@ void FNodeBuilder::BuildTree ()
C_InitTicker ("Building BSP", FRACUNIT); C_InitTicker ("Building BSP", FRACUNIT);
HackSeg = DWORD_MAX; HackSeg = DWORD_MAX;
HackMate = DWORD_MAX; HackMate = DWORD_MAX;
CreateNode (0, bbox); CreateNode (0, Segs.Size(), bbox);
CreateSubsectorsForReal (); CreateSubsectorsForReal ();
C_InitTicker (NULL, 0); C_InitTicker (NULL, 0);
} }
int FNodeBuilder::CreateNode (DWORD set, fixed_t bbox[4]) int FNodeBuilder::CreateNode (DWORD set, unsigned int count, fixed_t bbox[4])
{ {
node_t node; node_t node;
int skip, count, selstat; int skip, selstat;
DWORD splitseg; DWORD splitseg;
count = CountSegs (set); skip = int(count / MaxSegs);
skip = count / MaxSegs;
// When building GL nodes, count may not be an exact count of the number of segs
// in the set. That's okay, because we just use it to get a skip count, so an
// estimate is fine.
if ((selstat = SelectSplitter (set, node, splitseg, skip, true)) > 0 || if ((selstat = SelectSplitter (set, node, splitseg, skip, true)) > 0 ||
(skip > 0 && (selstat = SelectSplitter (set, node, splitseg, 1, true)) > 0) || (skip > 0 && (selstat = SelectSplitter (set, node, splitseg, 1, true)) > 0) ||
(selstat < 0 && (SelectSplitter (set, node, splitseg, skip, false) > 0 || (selstat < 0 && (SelectSplitter (set, node, splitseg, skip, false) > 0 ||
(skip > 0 && SelectSplitter (set, node, splitseg, 1, false)))) || (skip > 0 && SelectSplitter (set, node, splitseg, 1, false)))) ||
CheckSubsector (set, node, splitseg, count)) CheckSubsector (set, node, splitseg))
{ {
// Create a normal node // Create a normal node
DWORD set1, set2; DWORD set1, set2;
unsigned int count1, count2;
SplitSegs (set, node, splitseg, set1, set2); SplitSegs (set, node, splitseg, set1, set2, count1, count2);
D(PrintSet (1, set1)); D(PrintSet (1, set1));
D(Printf (PRINT_LOG, "(%d,%d) delta (%d,%d) from seg %d\n", node.x>>16, node.y>>16, node.dx>>16, node.dy>>16, splitseg)); D(Printf (PRINT_LOG, "(%d,%d) delta (%d,%d) from seg %d\n", node.x>>16, node.y>>16, node.dx>>16, node.dy>>16, splitseg));
D(PrintSet (2, set2)); D(PrintSet (2, set2));
node.intchildren[0] = CreateNode (set1, node.bbox[0]); node.intchildren[0] = CreateNode (set1, count1, node.bbox[0]);
node.intchildren[1] = CreateNode (set2, node.bbox[1]); node.intchildren[1] = CreateNode (set2, count2, node.bbox[1]);
bbox[BOXTOP] = MAX (node.bbox[0][BOXTOP], node.bbox[1][BOXTOP]); bbox[BOXTOP] = MAX (node.bbox[0][BOXTOP], node.bbox[1][BOXTOP]);
bbox[BOXBOTTOM] = MIN (node.bbox[0][BOXBOTTOM], node.bbox[1][BOXBOTTOM]); bbox[BOXBOTTOM] = MIN (node.bbox[0][BOXBOTTOM], node.bbox[1][BOXBOTTOM]);
bbox[BOXLEFT] = MIN (node.bbox[0][BOXLEFT], node.bbox[1][BOXLEFT]); bbox[BOXLEFT] = MIN (node.bbox[0][BOXLEFT], node.bbox[1][BOXLEFT]);
@ -306,24 +309,12 @@ int STACK_ARGS FNodeBuilder::SortSegs (const void *a, const void *b)
} }
} }
int FNodeBuilder::CountSegs (DWORD set) const
{
int count = 0;
while (set != DWORD_MAX)
{
count++;
set = Segs[set].next;
}
return count;
}
// Given a set of segs, checks to make sure they all belong to a single // Given a set of segs, checks to make sure they all belong to a single
// sector. If so, false is returned, and they become a subsector. If not, // sector. If so, false is returned, and they become a subsector. If not,
// a splitter is synthesized, and true is returned to continue processing // a splitter is synthesized, and true is returned to continue processing
// down this branch of the tree. // down this branch of the tree.
bool FNodeBuilder::CheckSubsector (DWORD set, node_t &node, DWORD &splitseg, int setsize) bool FNodeBuilder::CheckSubsector (DWORD set, node_t &node, DWORD &splitseg)
{ {
sector_t *sec; sector_t *sec;
DWORD seg; DWORD seg;
@ -768,8 +759,10 @@ int FNodeBuilder::Heuristic (node_t &node, DWORD set, bool honorNoSplit)
return score; return score;
} }
void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &outset0, DWORD &outset1) void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &outset0, DWORD &outset1, unsigned int &count0, unsigned int &count1)
{ {
unsigned int _count0 = 0;
unsigned int _count1 = 0;
outset0 = DWORD_MAX; outset0 = DWORD_MAX;
outset1 = DWORD_MAX; outset1 = DWORD_MAX;
@ -802,11 +795,13 @@ void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &ou
case 0: // seg is entirely in front case 0: // seg is entirely in front
seg->next = outset0; seg->next = outset0;
outset0 = set; outset0 = set;
_count0++;
break; break;
case 1: // seg is entirely in back case 1: // seg is entirely in back
seg->next = outset1; seg->next = outset1;
outset1 = set; outset1 = set;
_count1++;
break; break;
default: // seg needs to be split default: // seg needs to be split
@ -842,6 +837,8 @@ void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &ou
outset0 = seg2; outset0 = seg2;
Segs[set].next = outset1; Segs[set].next = outset1;
outset1 = set; outset1 = set;
_count0++;
_count1++;
// Also split the seg on the back side // Also split the seg on the back side
if (Segs[set].partner != DWORD_MAX) if (Segs[set].partner != DWORD_MAX)
@ -914,6 +911,8 @@ void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &ou
{ {
AddMinisegs (node, splitseg, outset0, outset1); AddMinisegs (node, splitseg, outset0, outset1);
} }
count0 = _count0;
count1 = _count1;
} }
void FNodeBuilder::SetNodeFromSeg (node_t &node, const FPrivSeg *pseg) const void FNodeBuilder::SetNodeFromSeg (node_t &node, const FPrivSeg *pseg) const

View file

@ -255,16 +255,15 @@ private:
bool GetPolyExtents (int polynum, fixed_t bbox[4]); bool GetPolyExtents (int polynum, fixed_t bbox[4]);
int MarkLoop (DWORD firstseg, int loopnum); int MarkLoop (DWORD firstseg, int loopnum);
void AddSegToBBox (fixed_t bbox[4], const FPrivSeg *seg); void AddSegToBBox (fixed_t bbox[4], const FPrivSeg *seg);
int CreateNode (DWORD set, fixed_t bbox[4]); int CreateNode (DWORD set, unsigned int count, fixed_t bbox[4]);
int CreateSubsector (DWORD set, fixed_t bbox[4]); int CreateSubsector (DWORD set, fixed_t bbox[4]);
void CreateSubsectorsForReal (); void CreateSubsectorsForReal ();
bool CheckSubsector (DWORD set, node_t &node, DWORD &splitseg, int setsize); bool CheckSubsector (DWORD set, node_t &node, DWORD &splitseg);
bool CheckSubsectorOverlappingSegs (DWORD set, node_t &node, DWORD &splitseg); bool CheckSubsectorOverlappingSegs (DWORD set, node_t &node, DWORD &splitseg);
bool ShoveSegBehind (DWORD set, node_t &node, DWORD seg, DWORD mate); int SelectSplitter (DWORD set, node_t &node, DWORD &splitseg, int step, bool nosplit); bool ShoveSegBehind (DWORD set, node_t &node, DWORD seg, DWORD mate); int SelectSplitter (DWORD set, node_t &node, DWORD &splitseg, int step, bool nosplit);
void SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &outset0, DWORD &outset1); void SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &outset0, DWORD &outset1, unsigned int &count0, unsigned int &count1);
DWORD SplitSeg (DWORD segnum, int splitvert, int v1InFront); DWORD SplitSeg (DWORD segnum, int splitvert, int v1InFront);
int Heuristic (node_t &node, DWORD set, bool honorNoSplit); int Heuristic (node_t &node, DWORD set, bool honorNoSplit);
int CountSegs (DWORD set) const;
// Returns: // Returns:
// 0 = seg is in front // 0 = seg is in front