- Add headers to generated CMake projects.
- Made SSELevel global so that ClassifyLineBackpatch can see it without being part of
  FNodeBuilder. With backpatching enabled, it's rather pointless to have a different one
  per nodebuilder instance, anyway.
- Change ClassifyLineBackpatch so it doesn't need any inline assembly to do its magic.
- Change the ClassifyLine functions to be extern "C" linkage.

SVN r2410 (trunk)
This commit is contained in:
Randy Heit 2010-07-04 21:11:25 +00:00
parent 983907fd20
commit 2de2b094ec
11 changed files with 358 additions and 377 deletions

View file

@ -127,11 +127,25 @@ set( SOURCES
nodebuild_classify_nosse2.cpp nodebuild_classify_nosse2.cpp
) )
if( WIN32 ) if( WIN32 )
set( SOURCES "${SOURCES} view.cpp" ) set( SOURCES "${SOURCES}" view.cpp )
else( WIN32 ) else( WIN32 )
add_definitions( -DNO_MAP_VIEWER ) add_definitions( -DNO_MAP_VIEWER )
endif( WIN32 ) endif( WIN32 )
set( HEADERS
blockmapbuilder.h
doomdata.h
getopt.h
nodebuild.h
processor.h
resource.h
sc_man.h
tarray.h
templates.h
wad.h
workdata.h
zdbsp.h )
if( SSE_MATTERS ) if( SSE_MATTERS )
if( FULL_SSE2 ) if( FULL_SSE2 )
message( STATUS "Using SSE2 math everywhere." ) message( STATUS "Using SSE2 math everywhere." )
@ -184,6 +198,6 @@ set( CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} ${REL_C_FLAGS}" )
set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${REL_C_FLAGS}" ) set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${REL_C_FLAGS}" )
set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${DEB_C_FLAGS} -D_DEBUG" ) set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${DEB_C_FLAGS} -D_DEBUG" )
add_executable( zdbsp ${SOURCES} ) add_executable( zdbsp ${SOURCES} ${HEADERS} )
target_link_libraries( zdbsp ${ZDBSP_LIBS} ${PROF_LIB} ) target_link_libraries( zdbsp ${ZDBSP_LIBS} ${PROF_LIB} )
include_directories( "${ZLIB_INCLUDE_DIR}" ) include_directories( "${ZLIB_INCLUDE_DIR}" )

View file

@ -113,6 +113,7 @@ bool ForceCompression = false;
bool GLOnly = false; bool GLOnly = false;
bool V5GLNodes = false; bool V5GLNodes = false;
bool HaveSSE1, HaveSSE2; bool HaveSSE1, HaveSSE2;
int SSELevel;
// PRIVATE DATA DEFINITIONS ------------------------------------------------ // PRIVATE DATA DEFINITIONS ------------------------------------------------

View file

@ -40,12 +40,11 @@
FNodeBuilder::FNodeBuilder (FLevel &level, FNodeBuilder::FNodeBuilder (FLevel &level,
TArray<FPolyStart> &polyspots, TArray<FPolyStart> &anchors, TArray<FPolyStart> &polyspots, TArray<FPolyStart> &anchors,
const char *name, bool makeGLnodes, BYTE sselevel) const char *name, bool makeGLnodes)
: Level(level), SegsStuffed(0), MapName(name) : Level(level), SegsStuffed(0), MapName(name)
{ {
VertexMap = new FVertexMap (*this, Level.MinX, Level.MinY, Level.MaxX, Level.MaxY); VertexMap = new FVertexMap (*this, Level.MinX, Level.MinY, Level.MaxX, Level.MaxY);
GLNodes = makeGLnodes; GLNodes = makeGLnodes;
SSELevel = sselevel;
FindUsedVertices (Level.Vertices, Level.NumVertices); FindUsedVertices (Level.Vertices, Level.NumVertices);
MakeSegsFromSides (); MakeSegsFromSides ();
FindPolyContainers (polyspots, anchors); FindPolyContainers (polyspots, anchors);
@ -508,7 +507,7 @@ int FNodeBuilder::Heuristic (node_t &node, DWORD set, bool honorNoSplit)
int realSegs[2] = { 0, 0 }; int realSegs[2] = { 0, 0 };
int specialSegs[2] = { 0, 0 }; int specialSegs[2] = { 0, 0 };
DWORD i = set; DWORD i = set;
int sidev1, sidev2; int sidev[2];
int side; int side;
bool splitter = false; bool splitter = false;
unsigned int max, m2, p, q; unsigned int max, m2, p, q;
@ -527,7 +526,7 @@ int FNodeBuilder::Heuristic (node_t &node, DWORD set, bool honorNoSplit)
} }
else else
{ {
side = ClassifyLine (node, test, sidev1, sidev2); side = ClassifyLine (node, &Vertices[test->v1], &Vertices[test->v2], sidev);
} }
switch (side) switch (side)
@ -538,9 +537,9 @@ int FNodeBuilder::Heuristic (node_t &node, DWORD set, bool honorNoSplit)
// The "right" thing to do in this case is to only reject it if there is // The "right" thing to do in this case is to only reject it if there is
// another nosplit seg from the same sector at this vertex. Note that a line // another nosplit seg from the same sector at this vertex. Note that a line
// that lies exactly on top of the splitter is okay. // that lies exactly on top of the splitter is okay.
if (test->loopnum && honorNoSplit && (sidev1 == 0 || sidev2 == 0)) if (test->loopnum && honorNoSplit && (sidev[0] == 0 || sidev[1] == 0))
{ {
if ((sidev1 | sidev2) != 0) if ((sidev[0] | sidev[1]) != 0)
{ {
max = Touched.Size(); max = Touched.Size();
for (p = 0; p < max; ++p) for (p = 0; p < max; ++p)
@ -752,18 +751,18 @@ void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &ou
FPrivSeg *seg = &Segs[set]; FPrivSeg *seg = &Segs[set];
int next = seg->next; int next = seg->next;
int sidev1, sidev2, side; int sidev[2], side;
if (HackSeg == set) if (HackSeg == set)
{ {
HackSeg = DWORD_MAX; HackSeg = DWORD_MAX;
side = 1; side = 1;
sidev1 = sidev2 = 0; sidev[0] = sidev[1] = 0;
hack = true; hack = true;
} }
else else
{ {
side = ClassifyLine (node, seg, sidev1, sidev2); side = ClassifyLine (node, &Vertices[seg->v1], &Vertices[seg->v2], sidev);
hack = false; hack = false;
} }
@ -810,7 +809,7 @@ void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &ou
Printf("SelectVertexClose selected endpoint of seg %u\n", (unsigned int)set); Printf("SelectVertexClose selected endpoint of seg %u\n", (unsigned int)set);
} }
seg2 = SplitSeg (set, vertnum, sidev1); seg2 = SplitSeg (set, vertnum, sidev[0]);
Segs[seg2].next = outset0; Segs[seg2].next = outset0;
outset0 = seg2; outset0 = seg2;
@ -821,7 +820,7 @@ void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &ou
if (Segs[set].partner != DWORD_MAX) if (Segs[set].partner != DWORD_MAX)
{ {
int partner1 = Segs[set].partner; int partner1 = Segs[set].partner;
int partner2 = SplitSeg (partner1, vertnum, sidev2); int partner2 = SplitSeg (partner1, vertnum, sidev[1]);
// The newly created seg stays in the same set as the // The newly created seg stays in the same set as the
// back seg because it has not been considered for splitting // back seg because it has not been considered for splitting
// yet. If it had been, then the front seg would have already // yet. If it had been, then the front seg would have already
@ -847,17 +846,17 @@ void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &ou
} }
if (side >= 0 && GLNodes) if (side >= 0 && GLNodes)
{ {
if (sidev1 == 0) if (sidev[0] == 0)
{ {
double dist1 = AddIntersection (node, seg->v1); double dist1 = AddIntersection (node, seg->v1);
if (sidev2 == 0) if (sidev[1] == 0)
{ {
double dist2 = AddIntersection (node, seg->v2); double dist2 = AddIntersection (node, seg->v2);
FSplitSharer share = { dist1, set, dist2 > dist1 }; FSplitSharer share = { dist1, set, dist2 > dist1 };
SplitSharers.Push (share); SplitSharers.Push (share);
} }
} }
else if (sidev2 == 0) else if (sidev[1] == 0)
{ {
AddIntersection (node, seg->v2); AddIntersection (node, seg->v2);
} }
@ -1058,39 +1057,31 @@ void FNodeBuilder::PrintSet (int l, DWORD set)
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
int FNodeBuilder::ClassifyLineBackpatch (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2) extern "C" int ClassifyLineBackpatch (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2])
{ {
// Select the routine based on SSELevel and patch the caller so that // Select the routine based on SSELevel and patch the caller so that
// they call that routine directly next time instead of going through here. // they call that routine directly next time instead of going through here.
int *calleroffset = (int *)__builtin_return_address(0) - 1; int *calleroffset = (int *)__builtin_return_address(0) - 1;
int diff; int diff;
int (*func)(FNodeBuilder *, node_t &, const FNodeBuilder::FPrivSeg *, int &, int &); int (*func)(node_t &, const FSimpleVert *, const FSimpleVert *, int[2]);
DWORD oldprotect; DWORD oldprotect;
// printf ("Patching for SSE %d\n", SSELevel); // printf ("Patching for SSE %d\n", SSELevel);
// I wasn't sure how to calculate the difference between the function addresses with C++
// (or if it's even possible), so here's some asm to do it instead:
if (SSELevel == 2) if (SSELevel == 2)
{ {
__asm ( func = ClassifyLineSSE2;
"movl $__ZN12FNodeBuilder16ClassifyLineSSE2ER6node_tPKNS_8FPrivSegERiS5_,%1\n\t" diff = (char *)ClassifyLineSSE2 - (char *)ClassifyLineBackpatch;
"movl $__ZN12FNodeBuilder16ClassifyLineSSE2ER6node_tPKNS_8FPrivSegERiS5_-__ZN12FNodeBuilder21ClassifyLineBackpatchER6node_tPKNS_8FPrivSegERiS5_,%0\n\t"
: "=r" (diff), "=r" (func));
} }
else if (SSELevel == 1) else if (SSELevel == 1)
{ {
__asm ( func = ClassifyLineSSE1;
"movl $__ZN12FNodeBuilder16ClassifyLineSSE1ER6node_tPKNS_8FPrivSegERiS5_,%1\n\t" diff = (char *)ClassifyLineSSE1 - (char *)ClassifyLineBackpatch;
"movl $__ZN12FNodeBuilder16ClassifyLineSSE1ER6node_tPKNS_8FPrivSegERiS5_-__ZN12FNodeBuilder21ClassifyLineBackpatchER6node_tPKNS_8FPrivSegERiS5_,%0\n\t"
: "=r" (diff), "=r" (func));
} }
else else
{ {
__asm ( func = ClassifyLine2;
"movl $__ZN12FNodeBuilder13ClassifyLine2ER6node_tPKNS_8FPrivSegERiS5_,%1\n\t" diff = (char *)ClassifyLine2 - (char *)ClassifyLineBackpatch;
"movl $__ZN12FNodeBuilder13ClassifyLine2ER6node_tPKNS_8FPrivSegERiS5_-__ZN12FNodeBuilder21ClassifyLineBackpatchER6node_tPKNS_8FPrivSegERiS5_,%0\n\t"
: "=r" (diff), "=r" (func));
} }
// Patch the caller. // Patch the caller.
@ -1101,6 +1092,6 @@ int FNodeBuilder::ClassifyLineBackpatch (node_t &node, const FPrivSeg *seg, int
} }
// And return by calling the real function. // And return by calling the real function.
return func (this, node, seg, sidev1, sidev2); return func (node, v1, v2, sidev);
} }
#endif #endif

View file

@ -45,6 +45,23 @@ private:
void PrintTree (const FEvent *event) const; void PrintTree (const FEvent *event) const;
}; };
struct FSimpleVert
{
fixed_t x, y;
};
extern "C"
{
int ClassifyLine2 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]);
#ifndef DISABLE_SSE
int ClassifyLineSSE1 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]);
int ClassifyLineSSE2 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]);
#if defined(_WIN32) && defined(__GNUC__) && !defined(DISABLE_BACKPATCH)
int ClassifyLineBackpatch (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]) __attribute__((noinline));
#endif
#endif
}
class FNodeBuilder class FNodeBuilder
{ {
struct FPrivSeg struct FPrivSeg
@ -67,9 +84,8 @@ class FNodeBuilder
bool planefront; bool planefront;
FPrivSeg *hashnext; FPrivSeg *hashnext;
}; };
struct FPrivVert struct FPrivVert : FSimpleVert
{ {
fixed_t x, y;
DWORD segs; // segs that use this vertex as v1 DWORD segs; // segs that use this vertex as v1
DWORD segs2; // segs that use this vertex as v2 DWORD segs2; // segs that use this vertex as v2
int index; int index;
@ -139,7 +155,7 @@ public:
FNodeBuilder (FLevel &level, FNodeBuilder (FLevel &level,
TArray<FPolyStart> &polyspots, TArray<FPolyStart> &anchors, TArray<FPolyStart> &polyspots, TArray<FPolyStart> &anchors,
const char *name, bool makeGLnodes, BYTE sselevel); const char *name, bool makeGLnodes);
~FNodeBuilder (); ~FNodeBuilder ();
void GetVertices (WideVertex *&verts, int &count); void GetVertices (WideVertex *&verts, int &count);
@ -179,7 +195,6 @@ private:
DWORD HackMate; // Seg to use in front of hack seg DWORD HackMate; // Seg to use in front of hack seg
FLevel &Level; FLevel &Level;
bool GLNodes; bool GLNodes;
int SSELevel;
// Progress meter stuff // Progress meter stuff
int SegsStuffed; int SegsStuffed;
@ -211,16 +226,7 @@ private:
// 1 = seg is in back // 1 = seg is in back
// -1 = seg cuts the node // -1 = seg cuts the node
inline int ClassifyLine (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2); inline int ClassifyLine (node_t &node, const FPrivVert *v1, const FPrivVert *v2, int sidev[2]);
int ClassifyLine2 (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2);
#ifndef DISABLE_SSE
int ClassifyLineSSE1 (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2);
int ClassifyLineSSE2 (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2);
#if defined(_WIN32) && defined(__GNUC__) && !defined(DISABLE_BACKPATCH)
int ClassifyLineBackpatch (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2) __attribute__((noinline));
#endif
#endif
void FixSplitSharers (); void FixSplitSharers ();
double AddIntersection (const node_t &node, int vertex); double AddIntersection (const node_t &node, int vertex);
@ -281,29 +287,28 @@ inline int FNodeBuilder::PointOnSide (int x, int y, int x1, int y1, int dx, int
return s_num > 0.0 ? -1 : 1; return s_num > 0.0 ? -1 : 1;
} }
inline int FNodeBuilder::ClassifyLine (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2) inline int FNodeBuilder::ClassifyLine (node_t &node, const FPrivVert *v1, const FPrivVert *v2, int sidev[2])
{ {
#ifdef DISABLE_SSE #ifdef DISABLE_SSE
return ClassifyLine2 (node, seg, sidev1, sidev2); return ClassifyLine2 (node, v1, v2, sidev);
#else #else
#if defined(__SSE2__) || defined(_M_IX64) #if defined(__SSE2__) || defined(_M_IX64)
// If compiling with SSE2 support everywhere, just use the SSE2 version. // If compiling with SSE2 support everywhere, just use the SSE2 version.
return ClassifyLineSSE2 (node, seg, sidev1, sidev2); return ClassifyLineSSE2 (node, v1, v2, sidev);
#elif defined(_MSC_VER) && _MSC_VER < 1300 #elif defined(_MSC_VER) && _MSC_VER < 1300
// VC 6 does not support SSE optimizations. // VC 6 does not support SSE optimizations.
return ClassifyLine2 (node, seg, sidev1, sidev2); return ClassifyLine2 (node, v1, v2, sidev);
#else #else
// Select the routine based on our flag. // Select the routine based on our flag.
#if defined(_WIN32) && defined(__GNUC__) && !defined(DISABLE_BACKPATCH) #if defined(_WIN32) && defined(__GNUC__) && !defined(DISABLE_BACKPATCH)
return ClassifyLineBackpatch (node, seg, sidev1, sidev2); return ClassifyLineBackpatch (node, v1, v2, sidev);
#else #else
if (SSELevel == 2) if (SSELevel == 2)
{ int foo = ClassifyLineSSE2 (node, seg, sidev1, sidev2); assert(foo == ClassifyLine2(node,seg,sidev1,sidev2)); return ClassifyLineSSE2 (node, v1, v2, sidev);
return foo; }
else if (SSELevel == 1) else if (SSELevel == 1)
return ClassifyLineSSE1 (node, seg, sidev1, sidev2); return ClassifyLineSSE1 (node, v1, v2, sidev);
else else
return ClassifyLine2 (node, seg, sidev1, sidev2); return ClassifyLine2 (node, v1, v2, sidev);
#endif #endif
#endif #endif
#endif #endif

View file

@ -23,11 +23,8 @@
#define FAR_ENOUGH 17179869184.f // 4<<32 #define FAR_ENOUGH 17179869184.f // 4<<32
int FNodeBuilder::ClassifyLine2 (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2) extern "C" int ClassifyLine2 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2])
{ {
const FPrivVert *v1 = &Vertices[seg->v1];
const FPrivVert *v2 = &Vertices[seg->v2];
double d_x1 = double(node.x); double d_x1 = double(node.x);
double d_y1 = double(node.y); double d_y1 = double(node.y);
double d_dx = double(node.dx); double d_dx = double(node.dx);
@ -46,13 +43,13 @@ int FNodeBuilder::ClassifyLine2 (node_t &node, const FPrivSeg *seg, int &sidev1,
{ {
if (s_num2 <= -FAR_ENOUGH) if (s_num2 <= -FAR_ENOUGH)
{ {
sidev1 = sidev2 = 1; sidev[0] = sidev[1] = 1;
return 1; return 1;
} }
if (s_num2 >= FAR_ENOUGH) if (s_num2 >= FAR_ENOUGH)
{ {
sidev1 = 1; sidev[0] = 1;
sidev2 = -1; sidev[1] = -1;
return -1; return -1;
} }
nears = 1; nears = 1;
@ -61,13 +58,13 @@ int FNodeBuilder::ClassifyLine2 (node_t &node, const FPrivSeg *seg, int &sidev1,
{ {
if (s_num2 >= FAR_ENOUGH) if (s_num2 >= FAR_ENOUGH)
{ {
sidev1 = sidev2 = -1; sidev[0] = sidev[1] = -1;
return 0; return 0;
} }
if (s_num2 <= -FAR_ENOUGH) if (s_num2 <= -FAR_ENOUGH)
{ {
sidev1 = -1; sidev[0] = -1;
sidev2 = 1; sidev[1] = 1;
return -1; return -1;
} }
nears = 1; nears = 1;
@ -85,41 +82,41 @@ int FNodeBuilder::ClassifyLine2 (node_t &node, const FPrivSeg *seg, int &sidev1,
double dist = s_num1 * s_num1 * l; double dist = s_num1 * s_num1 * l;
if (dist < SIDE_EPSILON*SIDE_EPSILON) if (dist < SIDE_EPSILON*SIDE_EPSILON)
{ {
sidev1 = 0; sidev[0] = 0;
} }
else else
{ {
sidev1 = s_num1 > 0.0 ? -1 : 1; sidev[0] = s_num1 > 0.0 ? -1 : 1;
} }
} }
else else
{ {
sidev1 = s_num1 > 0.0 ? -1 : 1; sidev[0] = s_num1 > 0.0 ? -1 : 1;
} }
if (nears & 1) if (nears & 1)
{ {
double dist = s_num2 * s_num2 * l; double dist = s_num2 * s_num2 * l;
if (dist < SIDE_EPSILON*SIDE_EPSILON) if (dist < SIDE_EPSILON*SIDE_EPSILON)
{ {
sidev2 = 0; sidev[1] = 0;
} }
else else
{ {
sidev2 = s_num2 > 0.0 ? -1 : 1; sidev[1] = s_num2 > 0.0 ? -1 : 1;
} }
} }
else else
{ {
sidev2 = s_num2 > 0.0 ? -1 : 1; sidev[1] = s_num2 > 0.0 ? -1 : 1;
} }
} }
else else
{ {
sidev1 = s_num1 > 0.0 ? -1 : 1; sidev[0] = s_num1 > 0.0 ? -1 : 1;
sidev2 = s_num2 > 0.0 ? -1 : 1; sidev[1] = s_num2 > 0.0 ? -1 : 1;
} }
if ((sidev1 | sidev2) == 0) if ((sidev[0] | sidev[1]) == 0)
{ // seg is coplanar with the splitter, so use its orientation to determine { // seg is coplanar with the splitter, so use its orientation to determine
// which child it ends up in. If it faces the same direction as the splitter, // which child it ends up in. If it faces the same direction as the splitter,
// it goes in front. Otherwise, it goes in back. // it goes in front. Otherwise, it goes in back.
@ -147,11 +144,11 @@ int FNodeBuilder::ClassifyLine2 (node_t &node, const FPrivSeg *seg, int &sidev1,
} }
} }
} }
else if (sidev1 <= 0 && sidev2 <= 0) else if (sidev[0] <= 0 && sidev[1] <= 0)
{ {
return 0; return 0;
} }
else if (sidev1 >= 0 && sidev2 >= 0) else if (sidev[0] >= 0 && sidev[1] >= 0)
{ {
return 1; return 1;
} }

View file

@ -29,11 +29,8 @@
// The reason it is SSE is because this file is explicitly compiled // The reason it is SSE is because this file is explicitly compiled
// with SSE math enabled, but the other files are not. // with SSE math enabled, but the other files are not.
int FNodeBuilder::ClassifyLineSSE1 (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2) extern "C" int ClassifyLineSSE1 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2])
{ {
const FPrivVert *v1 = &Vertices[seg->v1];
const FPrivVert *v2 = &Vertices[seg->v2];
double d_x1 = double(node.x); double d_x1 = double(node.x);
double d_y1 = double(node.y); double d_y1 = double(node.y);
double d_dx = double(node.dx); double d_dx = double(node.dx);
@ -52,13 +49,13 @@ int FNodeBuilder::ClassifyLineSSE1 (node_t &node, const FPrivSeg *seg, int &side
{ {
if (s_num2 <= -FAR_ENOUGH) if (s_num2 <= -FAR_ENOUGH)
{ {
sidev1 = sidev2 = 1; sidev[0] = sidev[1] = 1;
return 1; return 1;
} }
if (s_num2 >= FAR_ENOUGH) if (s_num2 >= FAR_ENOUGH)
{ {
sidev1 = 1; sidev[0] = 1;
sidev2 = -1; sidev[1] = -1;
return -1; return -1;
} }
nears = 1; nears = 1;
@ -67,13 +64,13 @@ int FNodeBuilder::ClassifyLineSSE1 (node_t &node, const FPrivSeg *seg, int &side
{ {
if (s_num2 >= FAR_ENOUGH) if (s_num2 >= FAR_ENOUGH)
{ {
sidev1 = sidev2 = -1; sidev[0] = sidev[1] = -1;
return 0; return 0;
} }
if (s_num2 <= -FAR_ENOUGH) if (s_num2 <= -FAR_ENOUGH)
{ {
sidev1 = -1; sidev[0] = -1;
sidev2 = 1; sidev[1] = 1;
return -1; return -1;
} }
nears = 1; nears = 1;
@ -91,41 +88,41 @@ int FNodeBuilder::ClassifyLineSSE1 (node_t &node, const FPrivSeg *seg, int &side
double dist = s_num1 * s_num1 * l; double dist = s_num1 * s_num1 * l;
if (dist < SIDE_EPSILON*SIDE_EPSILON) if (dist < SIDE_EPSILON*SIDE_EPSILON)
{ {
sidev1 = 0; sidev[0] = 0;
} }
else else
{ {
sidev1 = s_num1 > 0.0 ? -1 : 1; sidev[0] = s_num1 > 0.0 ? -1 : 1;
} }
} }
else else
{ {
sidev1 = s_num1 > 0.0 ? -1 : 1; sidev[0] = s_num1 > 0.0 ? -1 : 1;
} }
if (nears & 1) if (nears & 1)
{ {
double dist = s_num2 * s_num2 * l; double dist = s_num2 * s_num2 * l;
if (dist < SIDE_EPSILON*SIDE_EPSILON) if (dist < SIDE_EPSILON*SIDE_EPSILON)
{ {
sidev2 = 0; sidev[1] = 0;
} }
else else
{ {
sidev2 = s_num2 > 0.0 ? -1 : 1; sidev[1] = s_num2 > 0.0 ? -1 : 1;
} }
} }
else else
{ {
sidev2 = s_num2 > 0.0 ? -1 : 1; sidev[1] = s_num2 > 0.0 ? -1 : 1;
} }
} }
else else
{ {
sidev1 = s_num1 > 0.0 ? -1 : 1; sidev[0] = s_num1 > 0.0 ? -1 : 1;
sidev2 = s_num2 > 0.0 ? -1 : 1; sidev[1] = s_num2 > 0.0 ? -1 : 1;
} }
if ((sidev1 | sidev2) == 0) if ((sidev[0] | sidev[1]) == 0)
{ // seg is coplanar with the splitter, so use its orientation to determine { // seg is coplanar with the splitter, so use its orientation to determine
// which child it ends up in. If it faces the same direction as the splitter, // which child it ends up in. If it faces the same direction as the splitter,
// it goes in front. Otherwise, it goes in back. // it goes in front. Otherwise, it goes in back.
@ -153,11 +150,11 @@ int FNodeBuilder::ClassifyLineSSE1 (node_t &node, const FPrivSeg *seg, int &side
} }
} }
} }
else if (sidev1 <= 0 && sidev2 <= 0) else if (sidev[0] <= 0 && sidev[1] <= 0)
{ {
return 0; return 0;
} }
else if (sidev1 >= 0 && sidev2 >= 0) else if (sidev[0] >= 0 && sidev[1] >= 0)
{ {
return 1; return 1;
} }

View file

@ -29,11 +29,8 @@
// The reason it is SSE2 is because this file is explicitly compiled // The reason it is SSE2 is because this file is explicitly compiled
// with SSE2 math enabled, but the other files are not. // with SSE2 math enabled, but the other files are not.
int FNodeBuilder::ClassifyLineSSE2 (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2) extern "C" int ClassifyLineSSE2 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2])
{ {
const FPrivVert *v1 = &Vertices[seg->v1];
const FPrivVert *v2 = &Vertices[seg->v2];
double d_x1 = double(node.x); double d_x1 = double(node.x);
double d_y1 = double(node.y); double d_y1 = double(node.y);
double d_dx = double(node.dx); double d_dx = double(node.dx);
@ -52,13 +49,13 @@ int FNodeBuilder::ClassifyLineSSE2 (node_t &node, const FPrivSeg *seg, int &side
{ {
if (s_num2 <= -FAR_ENOUGH) if (s_num2 <= -FAR_ENOUGH)
{ {
sidev1 = sidev2 = 1; sidev[0] = sidev[1] = 1;
return 1; return 1;
} }
if (s_num2 >= FAR_ENOUGH) if (s_num2 >= FAR_ENOUGH)
{ {
sidev1 = 1; sidev[0] = 1;
sidev2 = -1; sidev[1] = -1;
return -1; return -1;
} }
nears = 1; nears = 1;
@ -67,13 +64,13 @@ int FNodeBuilder::ClassifyLineSSE2 (node_t &node, const FPrivSeg *seg, int &side
{ {
if (s_num2 >= FAR_ENOUGH) if (s_num2 >= FAR_ENOUGH)
{ {
sidev1 = sidev2 = -1; sidev[0] = sidev[1] = -1;
return 0; return 0;
} }
if (s_num2 <= -FAR_ENOUGH) if (s_num2 <= -FAR_ENOUGH)
{ {
sidev1 = -1; sidev[0] = -1;
sidev2 = 1; sidev[1] = 1;
return -1; return -1;
} }
nears = 1; nears = 1;
@ -91,41 +88,41 @@ int FNodeBuilder::ClassifyLineSSE2 (node_t &node, const FPrivSeg *seg, int &side
double dist = s_num1 * s_num1 * l; double dist = s_num1 * s_num1 * l;
if (dist < SIDE_EPSILON*SIDE_EPSILON) if (dist < SIDE_EPSILON*SIDE_EPSILON)
{ {
sidev1 = 0; sidev[0] = 0;
} }
else else
{ {
sidev1 = s_num1 > 0.0 ? -1 : 1; sidev[0] = s_num1 > 0.0 ? -1 : 1;
} }
} }
else else
{ {
sidev1 = s_num1 > 0.0 ? -1 : 1; sidev[0] = s_num1 > 0.0 ? -1 : 1;
} }
if (nears & 1) if (nears & 1)
{ {
double dist = s_num2 * s_num2 * l; double dist = s_num2 * s_num2 * l;
if (dist < SIDE_EPSILON*SIDE_EPSILON) if (dist < SIDE_EPSILON*SIDE_EPSILON)
{ {
sidev2 = 0; sidev[1] = 0;
} }
else else
{ {
sidev2 = s_num2 > 0.0 ? -1 : 1; sidev[1] = s_num2 > 0.0 ? -1 : 1;
} }
} }
else else
{ {
sidev2 = s_num2 > 0.0 ? -1 : 1; sidev[1] = s_num2 > 0.0 ? -1 : 1;
} }
} }
else else
{ {
sidev1 = s_num1 > 0.0 ? -1 : 1; sidev[0] = s_num1 > 0.0 ? -1 : 1;
sidev2 = s_num2 > 0.0 ? -1 : 1; sidev[1] = s_num2 > 0.0 ? -1 : 1;
} }
if ((sidev1 | sidev2) == 0) if ((sidev[0] | sidev[1]) == 0)
{ // seg is coplanar with the splitter, so use its orientation to determine { // seg is coplanar with the splitter, so use its orientation to determine
// which child it ends up in. If it faces the same direction as the splitter, // which child it ends up in. If it faces the same direction as the splitter,
// it goes in front. Otherwise, it goes in back. // it goes in front. Otherwise, it goes in back.
@ -153,11 +150,11 @@ int FNodeBuilder::ClassifyLineSSE2 (node_t &node, const FPrivSeg *seg, int &side
} }
} }
} }
else if (sidev1 <= 0 && sidev2 <= 0) else if (sidev[0] <= 0 && sidev[1] <= 0)
{ {
return 0; return 0;
} }
else if (sidev1 >= 0 && sidev2 >= 0) else if (sidev[0] >= 0 && sidev[1] >= 0)
{ {
return 1; return 1;
} }

View file

@ -30,20 +30,17 @@
// The reason it is SSE2 is because this file is explicitly compiled // The reason it is SSE2 is because this file is explicitly compiled
// with SSE2 math enabled, but the other files are not. // with SSE2 math enabled, but the other files are not.
int FNodeBuilder::ClassifyLineSSE2 (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2) extern "C" int ClassifyLineSSE2 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2])
{ {
const FPrivVert *v1 = &Vertices[seg->v1];
const FPrivVert *v2 = &Vertices[seg->v2];
__m128d xy, dxy, xyv1, xyv2; __m128d xy, dxy, xyv1, xyv2;
// Why does this intrinsic go through an MMX register, when it can just go through memory? // Why does this intrinsic go through an MMX register, when it can just go through memory?
// That would let it work with x64, too. // That would let it work with x64, too. (This only applies to VC++. GCC
xy = _mm_cvtpi32_pd(node.p64); // d_y1 d_x1 // is smarter and can load directly from memory without touching the MMX registers.)
dxy = _mm_cvtpi32_pd(node.d64); // d_dy d_dx xy = _mm_cvtpi32_pd(*(__m64*)&node.x); // d_y1 d_x1
xyv1 = _mm_cvtpi32_pd(v1->p64); // d_yv1 d_xv1 dxy = _mm_cvtpi32_pd(*(__m64*)&node.dx); // d_dy d_dx
xyv2 = _mm_cvtpi32_pd(v2->p64); // d_yv2 d_xv2 xyv1 = _mm_cvtpi32_pd(*(__m64*)&v1->x); // d_yv1 d_xv1
_mm_empty(); xyv2 = _mm_cvtpi32_pd(*(__m64*)&v2->x); // d_yv2 d_xv2
__m128d num1, num2, dyx; __m128d num1, num2, dyx;
@ -76,54 +73,56 @@ int FNodeBuilder::ClassifyLineSSE2 (node_t &node, const FPrivSeg *seg, int &side
}; };
struct struct
{ {
__int64 ni[2], pi[2]; int ni[4], pi[4];
};
}; };
} _;
_mm_storeu_pd(n, neg_check); _mm_storeu_pd(_.n, neg_check);
_mm_storeu_pd(p, pos_check); _mm_storeu_pd(_.p, pos_check);
int nears = 0; int nears = 0;
if (ni[0]) if (_.ni[0])
{ {
if (ni[1]) if (_.ni[2])
{ {
sidev1 = sidev2 = 1; sidev[0] = sidev[1] = 1;
return 1; return 1;
} }
if (pi[1]) if (_.pi[2])
{ {
sidev1 = 1; sidev[0] = 1;
sidev2 = -1; sidev[1] = -1;
return -1; return -1;
} }
nears = 1; nears = 1;
} }
else if (pi[0]) else if (_.pi[0])
{ {
if (pi[1]) if (_.pi[2])
{ {
sidev1 = sidev2 = -1; sidev[0] = sidev[1] = -1;
return 0; return 0;
} }
if (ni[1]) if (_.ni[2])
{ {
sidev1 = -1; sidev[0] = -1;
sidev2 = 1; sidev[1] = 1;
return -1; return -1;
} }
nears = 1; nears = 1;
} }
else else
{ {
nears = 2 | ((ni[1] | pi[1]) ? 0 : 1); nears = 2 | ((_.ni[2] | _.pi[2]) ? 0 : 1);
} }
__m128d zero = _mm_setzero_pd(); __m128d zero = _mm_setzero_pd();
__m128d posi = _mm_cmpgt_pd(num, zero); __m128d posi = _mm_cmpgt_pd(num, zero);
_mm_storeu_pd(p, posi); _mm_storeu_pd(_.p, posi);
int sv1 = _.pi[0] ? _.pi[0] : 1;
int sv2 = _.pi[2] ? _.pi[2] : 1;
if (nears) if (nears)
{ {
__m128d sqnum = _mm_mul_pd(num, num); __m128d sqnum = _mm_mul_pd(num, num);
@ -133,45 +132,20 @@ int FNodeBuilder::ClassifyLineSSE2 (node_t &node, const FPrivSeg *seg, int &side
__m128d dist = _mm_div_pd(sqnum, l); __m128d dist = _mm_div_pd(sqnum, l);
__m128d epsilon = _mm_set1_pd(SIDE_EPSILON); __m128d epsilon = _mm_set1_pd(SIDE_EPSILON);
__m128d close = _mm_cmplt_pd(dist, epsilon); __m128d close = _mm_cmplt_pd(dist, epsilon);
_mm_storeu_pd(n, close); _mm_storeu_pd(_.n, close);
if (nears & 2) if ((nears & 2) && _.ni[0])
{ {
if (ni[0]) sv1 = 0;
}
if ((nears & 1) && _.ni[2])
{ {
sidev1 = 0; sv2 = 0;
}
else
{
sidev1 = pi[0] ? -1 : 1;
} }
} }
else sidev[0] = sv1;
{ sidev[1] = sv2;
sidev1 = pi[0] ? -1 : 1;
}
if (nears & 1)
{
if (ni[1])
{
sidev2 = 0;
}
else
{
sidev2 = pi[1] ? -1 : 1;
}
}
else
{
sidev2 = pi[1] ? -1 : 1;
}
}
else
{
sidev1 = pi[0] ? -1 : 1;
sidev2 = pi[1] ? -1 : 1;
}
if ((sidev1 | sidev2) == 0) if ((sv1 | sv2) == 0)
{ // seg is coplanar with the splitter, so use its orientation to determine { // seg is coplanar with the splitter, so use its orientation to determine
// which child it ends up in. If it faces the same direction as the splitter, // which child it ends up in. If it faces the same direction as the splitter,
// it goes in front. Otherwise, it goes in back. // it goes in front. Otherwise, it goes in back.
@ -199,11 +173,11 @@ int FNodeBuilder::ClassifyLineSSE2 (node_t &node, const FPrivSeg *seg, int &side
} }
} }
} }
else if (sidev1 <= 0 && sidev2 <= 0) else if (sv1 <= 0 && sv2 <= 0)
{ {
return 0; return 0;
} }
else if (sidev1 >= 0 && sidev2 >= 0) else if (sv1 >= 0 && sv2 >= 0)
{ {
return 1; return 1;
} }

View file

@ -577,21 +577,19 @@ void FProcessor::Write (FWadWriter &out)
try try
{ {
int ssetype;
if (HaveSSE2) if (HaveSSE2)
{ {
ssetype = 2; SSELevel = 2;
} }
else if (HaveSSE1) else if (HaveSSE1)
{ {
ssetype = 1; SSELevel = 1;
} }
else else
{ {
ssetype = 0; SSELevel = 0;
} }
builder = new FNodeBuilder (Level, PolyStarts, PolyAnchors, Wad.LumpName (Lump), BuildGLNodes, ssetype); builder = new FNodeBuilder (Level, PolyStarts, PolyAnchors, Wad.LumpName (Lump), BuildGLNodes);
if (builder == NULL) if (builder == NULL)
{ {
throw std::runtime_error(" Not enough memory to build nodes!"); throw std::runtime_error(" Not enough memory to build nodes!");
@ -627,7 +625,7 @@ void FProcessor::Write (FWadWriter &out)
{ {
// Now repeat the process to obtain regular nodes // Now repeat the process to obtain regular nodes
delete builder; delete builder;
builder = new FNodeBuilder (Level, PolyStarts, PolyAnchors, Wad.LumpName (Lump), false, ssetype); builder = new FNodeBuilder (Level, PolyStarts, PolyAnchors, Wad.LumpName (Lump), false);
if (builder == NULL) if (builder == NULL)
{ {
throw std::runtime_error(" Not enough memory to build regular nodes!"); throw std::runtime_error(" Not enough memory to build regular nodes!");

View file

@ -46,6 +46,7 @@ extern bool CheckPolyobjs;
extern bool ShowMap; extern bool ShowMap;
extern bool CompressNodes, CompressGLNodes, ForceCompression, V5GLNodes; extern bool CompressNodes, CompressGLNodes, ForceCompression, V5GLNodes;
extern bool HaveSSE1, HaveSSE2; extern bool HaveSSE1, HaveSSE2;
extern int SSELevel;
#define FIXED_MAX INT_MAX #define FIXED_MAX INT_MAX

View file

@ -10,5 +10,11 @@ add_library( z
crc32.c crc32.c
deflate.c deflate.c
trees.c trees.c
zutil.c ) zutil.c
crc32.h
deflate.h
trees.h
zconf.h
zlib.h
zutil.h )
target_link_libraries( z ) target_link_libraries( z )