mirror of
https://github.com/ZDoom/zdbsp.git
synced 2024-11-22 11:51:19 +00:00
[ZDBSP]
- 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:
parent
733b292130
commit
af4a3b8447
2 changed files with 34 additions and 36 deletions
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue