]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - dpsoftrast.c
workaround for missing _mm_cvtss_f32 on some gcc versionsx
[xonotic/darkplaces.git] / dpsoftrast.c
index b0a5a3ad50f9651fa3a5849c6a634f053a3b76de..ae48e8cd33eef1f458cac263c8d99461c4b4e65c 100644 (file)
@@ -73,6 +73,10 @@ typedef qboolean bool;
 #ifdef SSE_POSSIBLE
 #include <emmintrin.h>
 
+#if defined(__GNUC__) && (__GNUC < 4 || __GNUC_MINOR__ < 6)
+       #define _mm_cvtss_f32(val) (__builtin_ia32_vec_ext_v4sf ((__v4sf)(val), 0))
+#endif
+
 #define MM_MALLOC(size) _mm_malloc(size, ATOMIC_SIZE)
 
 static void *MM_CALLOC(size_t nmemb, size_t size)
@@ -188,11 +192,14 @@ typedef ALIGN(struct DPSOFTRAST_State_Span_s
        int startx; // usable range (according to pixelmask)
        int endx; // usable range (according to pixelmask)
        unsigned char *pixelmask; // true for pixels that passed depth test, false for others
+       int depthbase; // depthbuffer value at x (add depthslope*startx to get first pixel's depthbuffer value)
+       int depthslope; // depthbuffer value pixel delta
 }
 DPSOFTRAST_State_Span);
 
 #define DPSOFTRAST_DRAW_MAXSPANS 1024
 #define DPSOFTRAST_DRAW_MAXTRIANGLES 128
+#define DPSOFTRAST_DRAW_MAXSPANLENGTH 256
 
 #define DPSOFTRAST_VALIDATE_FB 1
 #define DPSOFTRAST_VALIDATE_DEPTHFUNC 2
@@ -235,7 +242,8 @@ typedef ATOMIC(struct DPSOFTRAST_State_Thread_s
        int scissor[4];
        float depthrange[2];
        float polygonoffset[2];
-       ALIGN(float clipplane[4]);
+       float clipplane[4];
+       ALIGN(float fb_clipplane[4]);
 
        int shader_mode;
        int shader_permutation;
@@ -279,6 +287,7 @@ typedef ATOMIC(struct DPSOFTRAST_State_Thread_s
        int numtriangles;
        DPSOFTRAST_State_Span spans[DPSOFTRAST_DRAW_MAXSPANS];
        DPSOFTRAST_State_Triangle triangles[DPSOFTRAST_DRAW_MAXTRIANGLES];
+       unsigned char pixelmaskarray[DPSOFTRAST_DRAW_MAXSPANLENGTH+4]; // LordHavoc: padded to allow some termination bytes
 }
 DPSOFTRAST_State_Thread);
 
@@ -346,7 +355,9 @@ DPSOFTRAST_State dpsoftrast;
 #define DPSOFTRAST_DEPTHOFFSET (128.0f)
 #define DPSOFTRAST_BGRA8_FROM_RGBA32F(r,g,b,a) (((int)(r * 255.0f + 0.5f) << 16) | ((int)(g * 255.0f + 0.5f) << 8) | (int)(b * 255.0f + 0.5f) | ((int)(a * 255.0f + 0.5f) << 24))
 #define DPSOFTRAST_DEPTH32_FROM_DEPTH32F(d) ((int)(DPSOFTRAST_DEPTHSCALE * (1-d)))
-#define DPSOFTRAST_DRAW_MAXSPANLENGTH 256
+
+static void DPSOFTRAST_Draw_DepthTest(DPSOFTRAST_State_Thread *thread, DPSOFTRAST_State_Span *span);
+static void DPSOFTRAST_Draw_DepthWrite(const DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Span *span);
 
 static void DPSOFTRAST_RecalcViewport(const int *viewport, float *fb_viewportcenter, float *fb_viewportscale)
 {
@@ -376,6 +387,15 @@ static void DPSOFTRAST_RecalcThread(DPSOFTRAST_State_Thread *thread)
        }
 }
 
+static void DPSOFTRAST_RecalcClipPlane(DPSOFTRAST_State_Thread *thread)
+{
+       thread->fb_clipplane[0] = thread->clipplane[0] / thread->fb_viewportscale[1];
+       thread->fb_clipplane[1] = thread->clipplane[1] / thread->fb_viewportscale[2];
+       thread->fb_clipplane[2] = thread->clipplane[2] / thread->fb_viewportscale[3];
+       thread->fb_clipplane[3] = thread->clipplane[3] / thread->fb_viewportscale[0];
+       thread->fb_clipplane[3] -= thread->fb_viewportcenter[1]*thread->fb_clipplane[0] + thread->fb_viewportcenter[2]*thread->fb_clipplane[1] + thread->fb_viewportcenter[3]*thread->fb_clipplane[2] + thread->fb_viewportcenter[0]*thread->fb_clipplane[3];
+}
+
 static void DPSOFTRAST_RecalcFB(DPSOFTRAST_State_Thread *thread)
 {
        // calculate framebuffer scissor, viewport, viewport clipped by scissor,
@@ -397,6 +417,7 @@ static void DPSOFTRAST_RecalcFB(DPSOFTRAST_State_Thread *thread)
        thread->fb_scissor[3] = y2 - y1;
 
        DPSOFTRAST_RecalcViewport(thread->viewport, thread->fb_viewportcenter, thread->fb_viewportscale);
+       DPSOFTRAST_RecalcClipPlane(thread);
        DPSOFTRAST_RecalcThread(thread);
 }
 
@@ -1440,15 +1461,11 @@ DEFCOMMAND(24, ClipPlane, float clipplane[4];)
 static void DPSOFTRAST_Interpret_ClipPlane(DPSOFTRAST_State_Thread *thread, DPSOFTRAST_Command_ClipPlane *command)
 {
        memcpy(thread->clipplane, command->clipplane, 4*sizeof(float));
+       thread->validate |= DPSOFTRAST_VALIDATE_FB;
 }
 void DPSOFTRAST_ClipPlane(float x, float y, float z, float w)
 {
        DPSOFTRAST_Command_ClipPlane *command = DPSOFTRAST_ALLOCATECOMMAND(ClipPlane);
-       x /= dpsoftrast.fb_viewportscale[1];
-       y /= dpsoftrast.fb_viewportscale[2];
-       z /= dpsoftrast.fb_viewportscale[3];
-       w /= dpsoftrast.fb_viewportscale[0];
-       w -= dpsoftrast.fb_viewportcenter[1]*x + dpsoftrast.fb_viewportcenter[2]*y + dpsoftrast.fb_viewportcenter[3]*z + dpsoftrast.fb_viewportcenter[0]*w; 
        command->clipplane[0] = x;
        command->clipplane[1] = y;
        command->clipplane[2] = z;
@@ -2028,191 +2045,13 @@ void DPSOFTRAST_Draw_Span_Begin(DPSOFTRAST_State_Thread *thread, const DPSOFTRAS
        }
 }
 
-void DPSOFTRAST_Draw_Span_Finish(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span, const float * RESTRICT in4f)
-{
-       int x;
-       int startx = span->startx;
-       int endx = span->endx;
-       int d[4];
-       float a, b;
-       unsigned char * RESTRICT pixelmask = span->pixelmask;
-       unsigned char * RESTRICT pixel = (unsigned char *)dpsoftrast.fb_colorpixels[0];
-       if (!pixel)
-               return;
-       pixel += (span->y * dpsoftrast.fb_width + span->x) * 4;
-       // handle alphatest now (this affects depth writes too)
-       if (thread->alphatest)
-               for (x = startx;x < endx;x++)
-                       if (in4f[x*4+3] < 0.5f)
-                               pixelmask[x] = false;
-       // FIXME: this does not handle bigendian
-       switch(thread->fb_blendmode)
-       {
-       case DPSOFTRAST_BLENDMODE_OPAQUE:
-               for (x = startx;x < endx;x++)
-               {
-                       if (!pixelmask[x])
-                               continue;
-                       d[0] = (int)(in4f[x*4+2]*255.0f);if (d[0] > 255) d[0] = 255;
-                       d[1] = (int)(in4f[x*4+1]*255.0f);if (d[1] > 255) d[1] = 255;
-                       d[2] = (int)(in4f[x*4+0]*255.0f);if (d[2] > 255) d[2] = 255;
-                       d[3] = (int)(in4f[x*4+3]*255.0f);if (d[3] > 255) d[3] = 255;
-                       pixel[x*4+0] = d[0];
-                       pixel[x*4+1] = d[1];
-                       pixel[x*4+2] = d[2];
-                       pixel[x*4+3] = d[3];
-               }
-               break;
-       case DPSOFTRAST_BLENDMODE_ALPHA:
-               for (x = startx;x < endx;x++)
-               {
-                       if (!pixelmask[x])
-                               continue;
-                       a = in4f[x*4+3] * 255.0f;
-                       b = 1.0f - in4f[x*4+3];
-                       d[0] = (int)(in4f[x*4+2]*a+pixel[x*4+0]*b);if (d[0] > 255) d[0] = 255;
-                       d[1] = (int)(in4f[x*4+1]*a+pixel[x*4+1]*b);if (d[1] > 255) d[1] = 255;
-                       d[2] = (int)(in4f[x*4+0]*a+pixel[x*4+2]*b);if (d[2] > 255) d[2] = 255;
-                       d[3] = (int)(in4f[x*4+3]*a+pixel[x*4+3]*b);if (d[3] > 255) d[3] = 255;
-                       pixel[x*4+0] = d[0];
-                       pixel[x*4+1] = d[1];
-                       pixel[x*4+2] = d[2];
-                       pixel[x*4+3] = d[3];
-               }
-               break;
-       case DPSOFTRAST_BLENDMODE_ADDALPHA:
-               for (x = startx;x < endx;x++)
-               {
-                       if (!pixelmask[x])
-                               continue;
-                       a = in4f[x*4+3] * 255.0f;
-                       d[0] = (int)(in4f[x*4+2]*a+pixel[x*4+0]);if (d[0] > 255) d[0] = 255;
-                       d[1] = (int)(in4f[x*4+1]*a+pixel[x*4+1]);if (d[1] > 255) d[1] = 255;
-                       d[2] = (int)(in4f[x*4+0]*a+pixel[x*4+2]);if (d[2] > 255) d[2] = 255;
-                       d[3] = (int)(in4f[x*4+3]*a+pixel[x*4+3]);if (d[3] > 255) d[3] = 255;
-                       pixel[x*4+0] = d[0];
-                       pixel[x*4+1] = d[1];
-                       pixel[x*4+2] = d[2];
-                       pixel[x*4+3] = d[3];
-               }
-               break;
-       case DPSOFTRAST_BLENDMODE_ADD:
-               for (x = startx;x < endx;x++)
-               {
-                       if (!pixelmask[x])
-                               continue;
-                       d[0] = (int)(in4f[x*4+2]*255.0f+pixel[x*4+0]);if (d[0] > 255) d[0] = 255;
-                       d[1] = (int)(in4f[x*4+1]*255.0f+pixel[x*4+1]);if (d[1] > 255) d[1] = 255;
-                       d[2] = (int)(in4f[x*4+0]*255.0f+pixel[x*4+2]);if (d[2] > 255) d[2] = 255;
-                       d[3] = (int)(in4f[x*4+3]*255.0f+pixel[x*4+3]);if (d[3] > 255) d[3] = 255;
-                       pixel[x*4+0] = d[0];
-                       pixel[x*4+1] = d[1];
-                       pixel[x*4+2] = d[2];
-                       pixel[x*4+3] = d[3];
-               }
-               break;
-       case DPSOFTRAST_BLENDMODE_INVMOD:
-               for (x = startx;x < endx;x++)
-               {
-                       if (!pixelmask[x])
-                               continue;
-                       d[0] = (int)((1.0f-in4f[x*4+2])*pixel[x*4+0]);if (d[0] > 255) d[0] = 255;
-                       d[1] = (int)((1.0f-in4f[x*4+1])*pixel[x*4+1]);if (d[1] > 255) d[1] = 255;
-                       d[2] = (int)((1.0f-in4f[x*4+0])*pixel[x*4+2]);if (d[2] > 255) d[2] = 255;
-                       d[3] = (int)((1.0f-in4f[x*4+3])*pixel[x*4+3]);if (d[3] > 255) d[3] = 255;
-                       pixel[x*4+0] = d[0];
-                       pixel[x*4+1] = d[1];
-                       pixel[x*4+2] = d[2];
-                       pixel[x*4+3] = d[3];
-               }
-               break;
-       case DPSOFTRAST_BLENDMODE_MUL:
-               for (x = startx;x < endx;x++)
-               {
-                       if (!pixelmask[x])
-                               continue;
-                       d[0] = (int)(in4f[x*4+2]*pixel[x*4+0]);if (d[0] > 255) d[0] = 255;
-                       d[1] = (int)(in4f[x*4+1]*pixel[x*4+1]);if (d[1] > 255) d[1] = 255;
-                       d[2] = (int)(in4f[x*4+0]*pixel[x*4+2]);if (d[2] > 255) d[2] = 255;
-                       d[3] = (int)(in4f[x*4+3]*pixel[x*4+3]);if (d[3] > 255) d[3] = 255;
-                       pixel[x*4+0] = d[0];
-                       pixel[x*4+1] = d[1];
-                       pixel[x*4+2] = d[2];
-                       pixel[x*4+3] = d[3];
-               }
-               break;
-       case DPSOFTRAST_BLENDMODE_MUL2:
-               for (x = startx;x < endx;x++)
-               {
-                       if (!pixelmask[x])
-                               continue;
-                       d[0] = (int)(in4f[x*4+2]*pixel[x*4+0]*2.0f);if (d[0] > 255) d[0] = 255;
-                       d[1] = (int)(in4f[x*4+1]*pixel[x*4+1]*2.0f);if (d[1] > 255) d[1] = 255;
-                       d[2] = (int)(in4f[x*4+0]*pixel[x*4+2]*2.0f);if (d[2] > 255) d[2] = 255;
-                       d[3] = (int)(in4f[x*4+3]*pixel[x*4+3]*2.0f);if (d[3] > 255) d[3] = 255;
-                       pixel[x*4+0] = d[0];
-                       pixel[x*4+1] = d[1];
-                       pixel[x*4+2] = d[2];
-                       pixel[x*4+3] = d[3];
-               }
-               break;
-       case DPSOFTRAST_BLENDMODE_SUBALPHA:
-               for (x = startx;x < endx;x++)
-               {
-                       if (!pixelmask[x])
-                               continue;
-                       a = in4f[x*4+3] * -255.0f;
-                       d[0] = (int)(in4f[x*4+2]*a+pixel[x*4+0]);if (d[0] > 255) d[0] = 255;if (d[0] < 0) d[0] = 0;
-                       d[1] = (int)(in4f[x*4+1]*a+pixel[x*4+1]);if (d[1] > 255) d[1] = 255;if (d[1] < 0) d[1] = 0;
-                       d[2] = (int)(in4f[x*4+0]*a+pixel[x*4+2]);if (d[2] > 255) d[2] = 255;if (d[2] < 0) d[2] = 0;
-                       d[3] = (int)(in4f[x*4+3]*a+pixel[x*4+3]);if (d[3] > 255) d[3] = 255;if (d[3] < 0) d[3] = 0;
-                       pixel[x*4+0] = d[0];
-                       pixel[x*4+1] = d[1];
-                       pixel[x*4+2] = d[2];
-                       pixel[x*4+3] = d[3];
-               }
-               break;
-       case DPSOFTRAST_BLENDMODE_PSEUDOALPHA:
-               for (x = startx;x < endx;x++)
-               {
-                       if (!pixelmask[x])
-                               continue;
-                       a = 255.0f;
-                       b = 1.0f - in4f[x*4+3];
-                       d[0] = (int)(in4f[x*4+2]*a+pixel[x*4+0]*b);if (d[0] > 255) d[0] = 255;
-                       d[1] = (int)(in4f[x*4+1]*a+pixel[x*4+1]*b);if (d[1] > 255) d[1] = 255;
-                       d[2] = (int)(in4f[x*4+0]*a+pixel[x*4+2]*b);if (d[2] > 255) d[2] = 255;
-                       d[3] = (int)(in4f[x*4+3]*a+pixel[x*4+3]*b);if (d[3] > 255) d[3] = 255;
-                       pixel[x*4+0] = d[0];
-                       pixel[x*4+1] = d[1];
-                       pixel[x*4+2] = d[2];
-                       pixel[x*4+3] = d[3];
-               }
-               break;
-       case DPSOFTRAST_BLENDMODE_INVADD:
-               for (x = startx;x < endx;x++)
-               {
-                       if (!pixelmask[x])
-                               continue;
-                       d[0] = (int)((255.0f-pixel[x*4+2])*in4f[x*4+0] + pixel[x*4+2]);if (d[0] > 255) d[0] = 255;
-                       d[1] = (int)((255.0f-pixel[x*4+1])*in4f[x*4+1] + pixel[x*4+1]);if (d[1] > 255) d[1] = 255;
-                       d[2] = (int)((255.0f-pixel[x*4+0])*in4f[x*4+2] + pixel[x*4+0]);if (d[2] > 255) d[2] = 255;
-                       d[3] = (int)((255.0f-pixel[x*4+3])*in4f[x*4+3] + pixel[x*4+3]);if (d[3] > 255) d[3] = 255;
-                       pixel[x*4+0] = d[0];
-                       pixel[x*4+1] = d[1];
-                       pixel[x*4+2] = d[2];
-                       pixel[x*4+3] = d[3];
-               }
-               break;
-       }
-}
-
 void DPSOFTRAST_Draw_Span_FinishBGRA8(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span, const unsigned char* RESTRICT in4ub)
 {
 #ifdef SSE_POSSIBLE
        int x;
        int startx = span->startx;
        int endx = span->endx;
+       int maskx;
        int subx;
        const unsigned int * RESTRICT ini = (const unsigned int *)in4ub;
        unsigned char * RESTRICT pixelmask = span->pixelmask;
@@ -2234,9 +2073,25 @@ void DPSOFTRAST_Draw_Span_FinishBGRA8(DPSOFTRAST_State_Thread *thread, const DPS
        case DPSOFTRAST_BLENDMODE_ALPHA:
        case DPSOFTRAST_BLENDMODE_ADDALPHA:
        case DPSOFTRAST_BLENDMODE_SUBALPHA:
+               maskx = startx;
                for (x = startx;x < endx;x++)
-                       if (in4ub[x*4+3] < 1)
-                               pixelmask[x] = false;
+               {
+                       if (in4ub[x*4+3] >= 1)
+                       {
+                               startx = x;
+                               for (;;)
+                               {
+                                       while (++x < endx && in4ub[x*4+3] >= 1) ;
+                                       maskx = x;
+                                       if (x >= endx) break;
+                                       ++x;
+                                       while (++x < endx && in4ub[x*4+3] < 1) pixelmask[x] = false;
+                                       if (x >= endx) break;
+                               }
+                               break;
+                       }
+               }
+               endx = maskx;
                break;
        case DPSOFTRAST_BLENDMODE_OPAQUE:
        case DPSOFTRAST_BLENDMODE_ADD:
@@ -2264,10 +2119,22 @@ void DPSOFTRAST_Draw_Span_FinishBGRA8(DPSOFTRAST_State_Thread *thread, const DPS
                        if (x + 8 < endx)
                        {
                                // the 4-item search must be aligned or else it stalls badly
-                               if ((x & 3) && !pixelmask[x]) x++;
-                               if ((x & 3) && !pixelmask[x]) x++;
-                               if ((x & 3) && !pixelmask[x]) x++;
-                               while (*((unsigned int *)pixelmask + x) == 0x00000000)
+                               if ((x & 3) && !pixelmask[x]) 
+                               {
+                                       if(pixelmask[x]) goto endmasked;
+                                       x++;
+                                       if (x & 3)
+                                       {
+                                               if(pixelmask[x]) goto endmasked;
+                                               x++;
+                                               if (x & 3)
+                                               {
+                                                       if(pixelmask[x]) goto endmasked;
+                                                       x++;
+                                               }
+                                       }
+                               }
+                               while (*(unsigned int *)&pixelmask[x] == 0x00000000)
                                        x += 4;
                        }
 #endif
@@ -2277,15 +2144,28 @@ void DPSOFTRAST_Draw_Span_FinishBGRA8(DPSOFTRAST_State_Thread *thread, const DPS
                        if (x >= endx)
                                break;
                }
+       endmasked:
                // find length of subspan
                subx = x + 1;
 #if 1
-               if (x + 8 < endx)
+               if (subx + 8 < endx)
                {
-                       if ((subx & 3) && pixelmask[subx]) subx++;
-                       if ((subx & 3) && pixelmask[subx]) subx++;
-                       if ((subx & 3) && pixelmask[subx]) subx++;
-                       while (*((unsigned int *)pixelmask + subx) == 0x01010101)
+                       if (subx & 3)
+                       {
+                               if(!pixelmask[subx]) goto endunmasked;
+                               subx++;
+                               if (subx & 3)
+                               {
+                                       if(!pixelmask[subx]) goto endunmasked;
+                                       subx++;
+                                       if (subx & 3)
+                                       {
+                                               if(!pixelmask[subx]) goto endunmasked;
+                                               subx++;
+                                       }
+                               }
+                       }
+                       while (*(unsigned int *)&pixelmask[subx] == 0x01010101)
                                subx += 4;
                }
 #endif
@@ -2294,6 +2174,7 @@ void DPSOFTRAST_Draw_Span_FinishBGRA8(DPSOFTRAST_State_Thread *thread, const DPS
                // the checks can overshoot, so make sure to clip it...
                if (subx > endx)
                        subx = endx;
+       endunmasked:
                // now that we know the subspan length...  process!
                switch(thread->fb_blendmode)
                {
@@ -4705,81 +4586,89 @@ static const DPSOFTRAST_ShaderModeInfo DPSOFTRAST_ShaderModeTable[SHADERMODE_COU
        {2, DPSOFTRAST_VertexShader_DeferredLightSource,            DPSOFTRAST_PixelShader_DeferredLightSource,            {~0}},
 };
 
-void DPSOFTRAST_Draw_ProcessSpans(DPSOFTRAST_State_Thread *thread)
+static void DPSOFTRAST_Draw_DepthTest(DPSOFTRAST_State_Thread *thread, DPSOFTRAST_State_Span *span)
 {
-       int i;
        int x;
        int startx;
        int endx;
-//     unsigned int c;
-//     unsigned int *colorpixel;
        unsigned int *depthpixel;
-       float w;
-       float wslope;
        int depth;
        int depthslope;
        unsigned int d;
+       unsigned char *pixelmask;
+       DPSOFTRAST_State_Triangle *triangle;
+       triangle = &thread->triangles[span->triangle];
+       depthpixel = dpsoftrast.fb_depthpixels + span->y * dpsoftrast.fb_width + span->x;
+       startx = span->startx;
+       endx = span->endx;
+       depth = span->depthbase;
+       depthslope = span->depthslope;
+       pixelmask = thread->pixelmaskarray;
+       if (thread->depthtest && dpsoftrast.fb_depthpixels)
+       {
+               switch(thread->fb_depthfunc)
+               {
+               default:
+               case GL_ALWAYS:  for (x = startx, d = depth + depthslope*startx;x < endx;x++, d += depthslope) pixelmask[x] = true; break;
+               case GL_LESS:    for (x = startx, d = depth + depthslope*startx;x < endx;x++, d += depthslope) pixelmask[x] = depthpixel[x] < d; break;
+               case GL_LEQUAL:  for (x = startx, d = depth + depthslope*startx;x < endx;x++, d += depthslope) pixelmask[x] = depthpixel[x] <= d; break;
+               case GL_EQUAL:   for (x = startx, d = depth + depthslope*startx;x < endx;x++, d += depthslope) pixelmask[x] = depthpixel[x] == d; break;
+               case GL_GEQUAL:  for (x = startx, d = depth + depthslope*startx;x < endx;x++, d += depthslope) pixelmask[x] = depthpixel[x] >= d; break;
+               case GL_GREATER: for (x = startx, d = depth + depthslope*startx;x < endx;x++, d += depthslope) pixelmask[x] = depthpixel[x] > d; break;
+               case GL_NEVER:   for (x = startx, d = depth + depthslope*startx;x < endx;x++, d += depthslope) pixelmask[x] = false; break;
+               }
+               while (startx < endx && !pixelmask[startx])
+                       startx++;
+               while (endx > startx && !pixelmask[endx-1])
+                       endx--;
+       }
+       else
+       {
+               // no depth testing means we're just dealing with color...
+               memset(pixelmask + startx, 1, endx - startx);
+       }
+       span->pixelmask = pixelmask;
+       span->startx = startx;
+       span->endx = endx;
+}
+
+static void DPSOFTRAST_Draw_DepthWrite(const DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Span *span)
+{
+       int x, d, depth, depthslope, startx, endx;
+       const unsigned char *pixelmask;
+       unsigned int *depthpixel;
+       if (thread->depthmask && thread->depthtest && dpsoftrast.fb_depthpixels)
+       {
+               depth = span->depthbase;
+               depthslope = span->depthslope;
+               pixelmask = span->pixelmask;
+               startx = span->startx;
+               endx = span->endx;
+               depthpixel = dpsoftrast.fb_depthpixels + span->y * dpsoftrast.fb_width + span->x;
+               for (x = startx, d = depth + depthslope*startx;x < endx;x++, d += depthslope)
+                       if (pixelmask[x])
+                               depthpixel[x] = d;
+       }
+}
+
+void DPSOFTRAST_Draw_ProcessSpans(DPSOFTRAST_State_Thread *thread)
+{
+       int i;
        DPSOFTRAST_State_Triangle *triangle;
        DPSOFTRAST_State_Span *span;
-       unsigned char pixelmask[DPSOFTRAST_DRAW_MAXSPANLENGTH+4]; // LordHavoc: padded to allow some termination bytes
        for (i = 0; i < thread->numspans; i++)
        {
                span = &thread->spans[i];
                triangle = &thread->triangles[span->triangle];
-               if (thread->depthtest && dpsoftrast.fb_depthpixels)
-               {
-                       wslope = triangle->w[0];
-                       w = triangle->w[2] + span->x*wslope + span->y*triangle->w[1];
-                       depthslope = (int)(wslope*DPSOFTRAST_DEPTHSCALE);
-                       depth = (int)(w*DPSOFTRAST_DEPTHSCALE - DPSOFTRAST_DEPTHOFFSET*(thread->polygonoffset[1] + fabs(wslope)*thread->polygonoffset[0]));
-                       depthpixel = dpsoftrast.fb_depthpixels + span->y * dpsoftrast.fb_width + span->x;
-                       startx = span->startx;
-                       endx = span->endx;
-                       switch(thread->fb_depthfunc)
-                       {
-                       default:
-                       case GL_ALWAYS:  for (x = startx, d = depth + depthslope*startx;x < endx;x++, d += depthslope) pixelmask[x] = true; break;
-                       case GL_LESS:    for (x = startx, d = depth + depthslope*startx;x < endx;x++, d += depthslope) pixelmask[x] = depthpixel[x] < d; break;
-                       case GL_LEQUAL:  for (x = startx, d = depth + depthslope*startx;x < endx;x++, d += depthslope) pixelmask[x] = depthpixel[x] <= d; break;
-                       case GL_EQUAL:   for (x = startx, d = depth + depthslope*startx;x < endx;x++, d += depthslope) pixelmask[x] = depthpixel[x] == d; break;
-                       case GL_GEQUAL:  for (x = startx, d = depth + depthslope*startx;x < endx;x++, d += depthslope) pixelmask[x] = depthpixel[x] >= d; break;
-                       case GL_GREATER: for (x = startx, d = depth + depthslope*startx;x < endx;x++, d += depthslope) pixelmask[x] = depthpixel[x] > d; break;
-                       case GL_NEVER:   for (x = startx, d = depth + depthslope*startx;x < endx;x++, d += depthslope) pixelmask[x] = false; break;
-                       }
-                       //colorpixel = dpsoftrast.fb_colorpixels[0] + (span->y * dpsoftrast.fb_width + span->x) * 4;;
-                       //for (x = startx;x < endx;x++)
-                       //      colorpixel[x] = (depthpixel[x] & 0xFF000000) ? (0x00FF0000) : (depthpixel[x] & 0x00FF0000);
-                       // if there is no color buffer, skip pixel shader
-                       while (startx < endx && !pixelmask[startx])
-                               startx++;
-                       while (endx > startx && !pixelmask[endx-1])
-                               endx--;
-                       if (startx >= endx)
-                               continue; // no pixels to fill
-                       span->pixelmask = pixelmask;
-                       span->startx = startx;
-                       span->endx = endx;
-                       // run pixel shader if appropriate
-                       // do this before running depthmask code, to allow the pixelshader
-                       // to clear pixelmask values for alpha testing
-                       if (dpsoftrast.fb_colorpixels[0] && thread->fb_colormask)
-                               DPSOFTRAST_ShaderModeTable[thread->shader_mode].Span(thread, triangle, span);
-                       if (thread->depthmask)
-                               for (x = startx, d = depth + depthslope*startx;x < endx;x++, d += depthslope)
-                                       if (pixelmask[x])
-                                               depthpixel[x] = d;
-               }
-               else
-               {
-                       // no depth testing means we're just dealing with color...
-                       // if there is no color buffer, skip pixel shader
-                       if (dpsoftrast.fb_colorpixels[0] && thread->fb_colormask)
-                       {
-                               memset(pixelmask + span->startx, 1, span->endx - span->startx);
-                               span->pixelmask = pixelmask;
-                               DPSOFTRAST_ShaderModeTable[thread->shader_mode].Span(thread, triangle, span);
-                       }
-               }
+               DPSOFTRAST_Draw_DepthTest(thread, span);
+               if (span->startx >= span->endx)
+                       continue;
+               // run pixel shader if appropriate
+               // do this before running depthmask code, to allow the pixelshader
+               // to clear pixelmask values for alpha testing
+               if (dpsoftrast.fb_colorpixels[0] && thread->fb_colormask)
+                       DPSOFTRAST_ShaderModeTable[thread->shader_mode].Span(thread, triangle, span);
+               DPSOFTRAST_Draw_DepthWrite(thread, span);
        }
        thread->numspans = 0;
 }
@@ -5040,7 +4929,7 @@ static void DPSOFTRAST_Interpret_Draw(DPSOFTRAST_State_Thread *thread, DPSOFTRAS
                        clip0origin = 0;
                        clip0slope = 0;
                        clip0dir = 0;
-                       if(thread->clipplane[0] || thread->clipplane[1] || thread->clipplane[2])
+                       if(thread->fb_clipplane[0] || thread->fb_clipplane[1] || thread->fb_clipplane[2])
                        {
                                float cliporigin, clipxslope, clipyslope;
                                attriborigin = _mm_shuffle_ps(screen[1], screen[1], _MM_SHUFFLE(2, 2, 2, 2));
@@ -5049,9 +4938,9 @@ static void DPSOFTRAST_Interpret_Draw(DPSOFTRAST_State_Thread *thread, DPSOFTRAS
                                attribxslope = _mm_sub_ss(_mm_mul_ss(attribuxslope, attribedge1), _mm_mul_ss(attribvxslope, attribedge2));
                                attribyslope = _mm_sub_ss(_mm_mul_ss(attribvyslope, attribedge2), _mm_mul_ss(attribuyslope, attribedge1));
                                attriborigin = _mm_sub_ss(attriborigin, _mm_add_ss(_mm_mul_ss(attribxslope, x1), _mm_mul_ss(attribyslope, y1)));
-                               cliporigin = _mm_cvtss_f32(attriborigin)*thread->clipplane[2] + thread->clipplane[3];
-                               clipxslope = thread->clipplane[0] + _mm_cvtss_f32(attribxslope)*thread->clipplane[2];
-                               clipyslope = thread->clipplane[1] + _mm_cvtss_f32(attribyslope)*thread->clipplane[2];
+                               cliporigin = _mm_cvtss_f32(attriborigin)*thread->fb_clipplane[2] + thread->fb_clipplane[3];
+                               clipxslope = thread->fb_clipplane[0] + _mm_cvtss_f32(attribxslope)*thread->fb_clipplane[2];
+                               clipyslope = thread->fb_clipplane[1] + _mm_cvtss_f32(attribyslope)*thread->fb_clipplane[2];
                                if(clipxslope != 0)
                                {
                                        clip0origin = -cliporigin/clipxslope;
@@ -5134,6 +5023,7 @@ static void DPSOFTRAST_Interpret_Draw(DPSOFTRAST_State_Thread *thread, DPSOFTRAS
                        int yccmask = _mm_movemask_epi8(ycc);
                        int edge0p, edge0n, edge1p, edge1n;
                        int nexty;
+                       float w, wslope;
                        float clip0;
                        if (numpoints == 4)
                        {
@@ -5188,17 +5078,13 @@ static void DPSOFTRAST_Interpret_Draw(DPSOFTRAST_State_Thread *thread, DPSOFTRAS
                                xcoords = _mm_shuffle_ps(xcoords, xcoords, _MM_SHUFFLE(1, 0, 3, 2));
                                xslope = _mm_shuffle_ps(xslope, xslope, _MM_SHUFFLE(1, 0, 3, 2));
                        }
-                       clip0 = clip0origin + (y+0.5f)*clip0slope;
+                       clip0 = clip0origin + (y+0.5f)*clip0slope + 0.5f;
                        for(; y <= nexty; y++, xcoords = _mm_add_ps(xcoords, xslope), clip0 += clip0slope)
                        {
-                               int startx, endx, clipx = minx, offset;
+                               int startx, endx, offset;
                                startx = _mm_cvtss_si32(xcoords);
                                endx = _mm_cvtss_si32(_mm_movehl_ps(xcoords, xcoords));
-                               if (startx < minx) 
-                               {
-                                       if (startx < 0) startx = 0;
-                                       startx += (minx-startx)&~(DPSOFTRAST_DRAW_MAXSPANLENGTH-1);
-                               }
+                               if (startx < minx) startx = minx;
                                if (endx > maxx) endx = maxx;
                                if (startx >= endx) continue;
 
@@ -5209,8 +5095,7 @@ static void DPSOFTRAST_Interpret_Draw(DPSOFTRAST_State_Thread *thread, DPSOFTRAS
                                                if (startx < clip0) 
                                                {
                                                        if(endx <= clip0) continue;
-                                                       clipx = max((int)clip0, minx);
-                                                       startx += (clipx-startx)&~(DPSOFTRAST_DRAW_MAXSPANLENGTH-1); 
+                                                       startx = (int)clip0;
                                                }
                                        }
                                        else if (endx > clip0) 
@@ -5226,10 +5111,14 @@ static void DPSOFTRAST_Interpret_Draw(DPSOFTRAST_State_Thread *thread, DPSOFTRAS
                                        span->triangle = thread->numtriangles;
                                        span->x = offset;
                                        span->y = y;
-                                       span->startx = max(clipx - offset, 0);
+                                       span->startx = 0;
                                        span->endx = min(endx - offset, DPSOFTRAST_DRAW_MAXSPANLENGTH);
                                        if (span->startx >= span->endx)
-                                               continue; 
+                                               continue;
+                                       wslope = triangle->w[0];
+                                       w = triangle->w[2] + span->x*wslope + span->y*triangle->w[1];
+                                       span->depthslope = (int)(wslope*DPSOFTRAST_DEPTHSCALE);
+                                       span->depthbase = (int)(w*DPSOFTRAST_DEPTHSCALE - DPSOFTRAST_DEPTHOFFSET*(thread->polygonoffset[1] + fabs(wslope)*thread->polygonoffset[0]));
                                        if (++thread->numspans >= DPSOFTRAST_DRAW_MAXSPANS)
                                                DPSOFTRAST_Draw_ProcessSpans(thread);
                                }
@@ -5555,6 +5444,7 @@ int DPSOFTRAST_Init(int width, int height, int numthreads, int interlace, unsign
                DPSOFTRAST_State_Thread *thread = &dpsoftrast.threads[i];
                thread->index = i;
                thread->cullface = GL_BACK;
+               thread->colormask[0] = 1; 
                thread->colormask[1] = 1;
                thread->colormask[2] = 1;
                thread->colormask[3] = 1;
@@ -5584,8 +5474,6 @@ int DPSOFTRAST_Init(int width, int height, int numthreads, int interlace, unsign
                thread->clipplane[2] = 0;
                thread->clipplane[3] = 1;
        
-               DPSOFTRAST_RecalcThread(thread);
-       
                thread->numspans = 0;
                thread->numtriangles = 0;
                thread->commandoffset = 0;