- Do not count the segs in a separate pass in CreateNode(). This can be computed trivially
  in SplitSegs() as the sets are being built.
- Calculate jump offsets for backpatching without reading the original value. This makes it
  thread-safe (if that ever becomes an issue).

SVN r2478 (trunk)
This commit is contained in:
Randy Heit 2010-07-31 04:30:33 +00:00
parent 733b292130
commit af4a3b8447
2 changed files with 34 additions and 36 deletions

View file

@ -67,35 +67,38 @@ void FNodeBuilder::BuildTree ()
fprintf (stderr, " BSP: 0.0%%\r"); fprintf (stderr, " BSP: 0.0%%\r");
HackSeg = DWORD_MAX; HackSeg = DWORD_MAX;
HackMate = DWORD_MAX; HackMate = DWORD_MAX;
CreateNode (0, bbox); CreateNode (0, Segs.Size(), bbox);
CreateSubsectorsForReal (); CreateSubsectorsForReal ();
fprintf (stderr, " BSP: 100.0%%\n"); fprintf (stderr, " BSP: 100.0%%\n");
} }
DWORD FNodeBuilder::CreateNode (DWORD set, fixed_t bbox[4]) DWORD 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); // When building GL nodes, count may not be an exact count of the number of segs
skip = count / MaxSegs; // in this set. That's okay, because we just use it to get a skip count, so an
// estimate is fine.
skip = int(count / MaxSegs);
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 ("(%d,%d) delta (%d,%d) from seg %d\n", node.x>>16, node.y>>16, node.dx>>16, node.dy>>16, splitseg)); D(Printf ("(%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]);
@ -273,24 +276,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)
{ {
int sec; int sec;
DWORD seg; DWORD seg;
@ -737,8 +728,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;
@ -772,12 +765,14 @@ void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &ou
seg->next = outset0; seg->next = outset0;
//Printf ("%u in front\n", set); //Printf ("%u in front\n", set);
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;
//Printf ("%u in back\n", set); //Printf ("%u in back\n", set);
outset1 = set; outset1 = set;
_count1++;
break; break;
default: // seg needs to be split default: // seg needs to be split
@ -815,6 +810,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)
@ -892,6 +889,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
@ -1077,7 +1076,7 @@ int ClassifyLineBackpatchC (node_t &node, const FSimpleVert *v1, const FSimpleVe
DWORD oldprotect; DWORD oldprotect;
#ifdef __GNUC__ #ifdef __GNUC__
calleroffset = (int *)__builtin_return_address(0) - 1; calleroffset = (int *)__builtin_return_address(0);
#else #else
calleroffset = CallerOffset; calleroffset = CallerOffset;
#endif #endif
@ -1086,34 +1085,35 @@ int ClassifyLineBackpatchC (node_t &node, const FSimpleVert *v1, const FSimpleVe
if (SSELevel == 2) if (SSELevel == 2)
{ {
func = ClassifyLineSSE2; func = ClassifyLineSSE2;
diff = (char *)ClassifyLineSSE2 - (char *)ClassifyLineBackpatch; diff = (char *)ClassifyLineSSE2 - (char *)calleroffset;
} }
else if (SSELevel == 1) else if (SSELevel == 1)
{ {
func = ClassifyLineSSE1; func = ClassifyLineSSE1;
diff = (char *)ClassifyLineSSE1 - (char *)ClassifyLineBackpatch; diff = (char *)ClassifyLineSSE1 - (char *)calleroffset;
} }
else else
{ {
func = ClassifyLine2; func = ClassifyLine2;
diff = (char *)ClassifyLine2 - (char *)ClassifyLineBackpatch; diff = (char *)ClassifyLine2 - (char *)calleroffset;
} }
// Patch the caller. // Patch the caller.
calleroffset--;
#ifdef _WIN32 #ifdef _WIN32
if (VirtualProtect (calleroffset, 4, PAGE_EXECUTE_READWRITE, &oldprotect)) if (VirtualProtect (calleroffset, sizeof(void*), PAGE_EXECUTE_READWRITE, &oldprotect))
#else #else
// must make this page-aligned for mprotect // must make this page-aligned for mprotect
long pagesize = sysconf(_SC_PAGESIZE); long pagesize = sysconf(_SC_PAGESIZE);
char *callerpage = (char *)((intptr_t)calleroffset & ~(pagesize - 1)); char *callerpage = (char *)((intptr_t)calleroffset & ~(pagesize - 1));
size_t protectlen = (intptr_t)calleroffset + 4 - (intptr_t)callerpage; size_t protectlen = (intptr_t)calleroffset + sizeof(void*) - (intptr_t)callerpage;
int ptect; int ptect;
if (!(ptect = mprotect(callerpage, protectlen, PROT_READ|PROT_WRITE|PROT_EXEC))) if (!(ptect = mprotect(callerpage, protectlen, PROT_READ|PROT_WRITE|PROT_EXEC)))
#endif #endif
{ {
*calleroffset += diff; *calleroffset = diff;
#ifdef _WIN32 #ifdef _WIN32
VirtualProtect (calleroffset, 4, oldprotect, &oldprotect); VirtualProtect (calleroffset, sizeof(void*), oldprotect, &oldprotect);
#else #else
mprotect(callerpage, protectlen, PROT_READ|PROT_EXEC); mprotect(callerpage, protectlen, PROT_READ|PROT_EXEC);
#endif #endif
@ -1135,7 +1135,6 @@ extern "C" __declspec(noinline) __declspec(naked) int ClassifyLineBackpatch (nod
__asm __asm
{ {
mov eax, [esp] mov eax, [esp]
sub eax, 4
mov CallerOffset, eax mov CallerOffset, eax
jmp ClassifyLineBackpatchC jmp ClassifyLineBackpatchC
} }

View file

@ -213,17 +213,16 @@ 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);
DWORD CreateNode (DWORD set, fixed_t bbox[4]); DWORD CreateNode (DWORD set, unsigned int count, fixed_t bbox[4]);
DWORD CreateSubsector (DWORD set, fixed_t bbox[4]); DWORD 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); bool ShoveSegBehind (DWORD set, node_t &node, DWORD seg, DWORD mate);
int SelectSplitter (DWORD set, node_t &node, DWORD &splitseg, int step, bool nosplit); 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