Merge branch 'mesa_7_5_branch'
authorBrian Paul <brianp@vmware.com>
Wed, 5 Aug 2009 20:13:48 +0000 (14:13 -0600)
committerBrian Paul <brianp@vmware.com>
Wed, 5 Aug 2009 20:13:48 +0000 (14:13 -0600)
Conflicts:

src/mesa/main/state.c

docs/relnotes-7.5.1.html
progs/xdemos/glxcontexts.c
progs/xdemos/glxswapcontrol.c
src/gallium/auxiliary/util/u_blit.c
src/mesa/drivers/dri/intel/intel_batchbuffer.c
src/mesa/main/fbobject.c
src/mesa/main/image.c
src/mesa/main/image.h
src/mesa/state_tracker/st_cb_blit.c
src/mesa/state_tracker/st_extensions.c
src/mesa/swrast/s_blit.c

index 0f475ad..2a7661f 100644 (file)
@@ -43,6 +43,11 @@ tbd
 <h2>Bug fixes</h2>
 <ul>
 <li>Added missing GLEW library to MesaDemos tarballs.
+<li>Fixed swapbuffers jerkiness in Doom3/etc in Intel drivers.
+<li>Fixed front buffer rendering bug in Intel drivers.
+<li>Fixed minor GLX memory leaks.
+<li>Fixed some texture env / fragment program state bugs.
+<li>Fixed some Gallium glBlitFramebuffer() bugs
 </ul>
 
 
index 481749b..9f83679 100644 (file)
@@ -378,6 +378,9 @@ make_window( Display *dpy, const char *name,
    scrnum = DefaultScreen( dpy );
    root = RootWindow( dpy, scrnum );
 
+   if (visinfo)
+          XFree(visinfo);
+
    visinfo = glXChooseVisual( dpy, scrnum, attribs );
    if (!visinfo) {
       printf("Error: couldn't get an RGB, Double-buffered visual\n");
index df9f7ad..cd60d46 100644 (file)
@@ -587,6 +587,9 @@ event_loop(Display *dpy, Window win)
       angle += 2.0;
 
       draw();
+
+      glXSwapBuffers(dpy, win);
+
       if ( get_frame_usage != NULL ) {
         GLfloat   temp;
         
@@ -594,8 +597,6 @@ event_loop(Display *dpy, Window win)
         frame_usage += temp;
       }
 
-      glXSwapBuffers(dpy, win);
-
       /* calc framerate */
       {
          static int t0 = -1;
index 414cf91..f7cc7dd 100644 (file)
@@ -155,7 +155,11 @@ util_destroy_blit(struct blit_state *ctx)
 }
 
 
-static unsigned get_next_slot( struct blit_state *ctx )
+/**
+ * Get offset of next free slot in vertex buffer for quad vertices.
+ */
+static unsigned
+get_next_slot( struct blit_state *ctx )
 {
    const unsigned max_slots = 4096 / sizeof ctx->vertices;
 
@@ -173,7 +177,6 @@ static unsigned get_next_slot( struct blit_state *ctx )
 }
                                
 
-
 /**
  * Setup vertex data for the textured quad we'll draw.
  * Note: y=0=top
@@ -260,9 +263,38 @@ setup_vertex_data_tex(struct blit_state *ctx,
 
    return offset;
 }
+
+
+/**
+ * \return TRUE if two regions overlap, FALSE otherwise
+ */
+static boolean
+regions_overlap(int srcX0, int srcY0,
+                int srcX1, int srcY1,
+                int dstX0, int dstY0,
+                int dstX1, int dstY1)
+{
+   if (MAX2(srcX0, srcX1) < MIN2(dstX0, dstX1))
+      return FALSE; /* src completely left of dst */
+
+   if (MAX2(dstX0, dstX1) < MIN2(srcX0, srcX1))
+      return FALSE; /* dst completely left of src */
+
+   if (MAX2(srcY0, srcY1) < MIN2(dstY0, dstY1))
+      return FALSE; /* src completely above dst */
+
+   if (MAX2(dstY0, dstY1) < MIN2(srcY0, srcY1))
+      return FALSE; /* dst completely above src */
+
+   return TRUE; /* some overlap */
+}
+
+
 /**
  * Copy pixel block from src surface to dst surface.
  * Overlapping regions are acceptable.
+ * Flipping and stretching are supported.
+ * XXX what about clipping???
  * XXX need some control over blitting Z and/or stencil.
  */
 void
@@ -285,10 +317,40 @@ util_blit_pixels(struct blit_state *ctx,
    const int srcLeft = MIN2(srcX0, srcX1);
    const int srcTop = MIN2(srcY0, srcY1);
    unsigned offset;
+   boolean overlap;
 
    assert(filter == PIPE_TEX_MIPFILTER_NEAREST ||
           filter == PIPE_TEX_MIPFILTER_LINEAR);
 
+   assert(screen->is_format_supported(screen, src->format, PIPE_TEXTURE_2D,
+                                      PIPE_TEXTURE_USAGE_SAMPLER, 0));
+   assert(screen->is_format_supported(screen, dst->format, PIPE_TEXTURE_2D,
+                                      PIPE_TEXTURE_USAGE_SAMPLER, 0));
+
+   /* do the regions overlap? */
+   overlap = (src == dst) && regions_overlap(srcX0, srcY0, srcX1, srcY1,
+                                             dstX0, dstY0, dstX1, dstY1);
+
+   /*
+    * Check for simple case:  no format conversion, no flipping, no stretching,
+    * no overlapping.
+    */
+   if (dst->format == src->format &&
+       srcX0 < srcX1 &&
+       dstX0 < dstX1 &&
+       srcY0 < srcY1 &&
+       dstY0 < dstY1 &&
+       (dstX1 - dstX0) == (srcX1 - srcX0) &&
+       (dstY1 - dstY0) == (srcY1 - srcY0) &&
+       !overlap) {
+      /* FIXME: this will most surely fail for overlapping rectangles */
+      pipe->surface_copy(pipe,
+                        dst, dstX0, dstY0, /* dest */
+                        src, srcX0, srcY0, /* src */
+                        srcW, srcH);       /* size */
+      return;
+   }
+   
    if (srcLeft != srcX0) {
       /* left-right flip */
       int tmp = dstX0;
@@ -303,20 +365,6 @@ util_blit_pixels(struct blit_state *ctx,
       dstY1 = tmp;
    }
 
-   assert(screen->is_format_supported(screen, src->format, PIPE_TEXTURE_2D,
-                                      PIPE_TEXTURE_USAGE_SAMPLER, 0));
-   assert(screen->is_format_supported(screen, dst->format, PIPE_TEXTURE_2D,
-                                      PIPE_TEXTURE_USAGE_SAMPLER, 0));
-
-   if(dst->format == src->format && (dstX1 - dstX0) == srcW && (dstY1 - dstY0) == srcH) {
-      /* FIXME: this will most surely fail for overlapping rectangles */
-      pipe->surface_copy(pipe,
-                        dst, dstX0, dstY0,   /* dest */
-                        src, srcX0, srcY0, /* src */
-                        srcW, srcH);     /* size */
-      return;
-   }
-   
    assert(screen->is_format_supported(screen, dst->format, PIPE_TEXTURE_2D,
                                       PIPE_TEXTURE_USAGE_RENDER_TARGET, 0));
 
index e94b836..6aa36d1 100644 (file)
@@ -201,6 +201,11 @@ _intel_batchbuffer_flush(struct intel_batchbuffer *batch, const char *file,
       drm_intel_bo_reference(intel->first_post_swapbuffers_batch);
    }
 
+   if (intel->first_post_swapbuffers_batch == NULL) {
+      intel->first_post_swapbuffers_batch = intel->batch->buf;
+      drm_intel_bo_reference(intel->first_post_swapbuffers_batch);
+   }
+
    if (used == 0) {
       batch->cliprect_mode = IGNORE_CLIPRECTS;
       return;
index 83301f1..ab91fbc 100644 (file)
@@ -2038,7 +2038,9 @@ _mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
    if (mask & GL_STENCIL_BUFFER_BIT) {
       struct gl_renderbuffer *readRb = readFb->_StencilBuffer;
       struct gl_renderbuffer *drawRb = drawFb->_StencilBuffer;
-      if (readRb->StencilBits != drawRb->StencilBits) {
+      if (!readRb ||
+          !drawRb ||
+          readRb->StencilBits != drawRb->StencilBits) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
                      "glBlitFramebufferEXT(stencil buffer size mismatch");
          return;
@@ -2048,7 +2050,9 @@ _mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
    if (mask & GL_DEPTH_BUFFER_BIT) {
       struct gl_renderbuffer *readRb = readFb->_DepthBuffer;
       struct gl_renderbuffer *drawRb = drawFb->_DepthBuffer;
-      if (readRb->DepthBits != drawRb->DepthBits) {
+      if (!readRb ||
+          !drawRb ||
+          readRb->DepthBits != drawRb->DepthBits) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
                      "glBlitFramebufferEXT(depth buffer size mismatch");
          return;
index 090e5eb..e0e8548 100644 (file)
@@ -5335,3 +5335,181 @@ _mesa_clip_to_region(GLint xmin, GLint ymin,
 
    return GL_TRUE;
 }
+
+
+/**
+ * Clip dst coords against Xmax (or Ymax).
+ */
+static INLINE void
+clip_right_or_top(GLint *srcX0, GLint *srcX1,
+                  GLint *dstX0, GLint *dstX1,
+                  GLint maxValue)
+{
+   GLfloat t, bias;
+
+   if (*dstX1 > maxValue) {
+      /* X1 outside right edge */
+      ASSERT(*dstX0 < maxValue); /* X0 should be inside right edge */
+      t = (GLfloat) (maxValue - *dstX0) / (GLfloat) (*dstX1 - *dstX0);
+      /* chop off [t, 1] part */
+      ASSERT(t >= 0.0 && t <= 1.0);
+      *dstX1 = maxValue;
+      bias = (*srcX0 < *srcX1) ? 0.5 : -0.5;
+      *srcX1 = *srcX0 + (GLint) (t * (*srcX1 - *srcX0) + bias);
+   }
+   else if (*dstX0 > maxValue) {
+      /* X0 outside right edge */
+      ASSERT(*dstX1 < maxValue); /* X1 should be inside right edge */
+      t = (GLfloat) (maxValue - *dstX1) / (GLfloat) (*dstX0 - *dstX1);
+      /* chop off [t, 1] part */
+      ASSERT(t >= 0.0 && t <= 1.0);
+      *dstX0 = maxValue;
+      bias = (*srcX0 < *srcX1) ? -0.5 : 0.5;
+      *srcX0 = *srcX1 + (GLint) (t * (*srcX0 - *srcX1) + bias);
+   }
+}
+
+
+/**
+ * Clip dst coords against Xmin (or Ymin).
+ */
+static INLINE void
+clip_left_or_bottom(GLint *srcX0, GLint *srcX1,
+                    GLint *dstX0, GLint *dstX1,
+                    GLint minValue)
+{
+   GLfloat t, bias;
+
+   if (*dstX0 < minValue) {
+      /* X0 outside left edge */
+      ASSERT(*dstX1 > minValue); /* X1 should be inside left edge */
+      t = (GLfloat) (minValue - *dstX0) / (GLfloat) (*dstX1 - *dstX0);
+      /* chop off [0, t] part */
+      ASSERT(t >= 0.0 && t <= 1.0);
+      *dstX0 = minValue;
+      bias = (*srcX0 < *srcX1) ? 0.5 : -0.5; /* flipped??? */
+      *srcX0 = *srcX0 + (GLint) (t * (*srcX1 - *srcX0) + bias);
+   }
+   else if (*dstX1 < minValue) {
+      /* X1 outside left edge */
+      ASSERT(*dstX0 > minValue); /* X0 should be inside left edge */
+      t = (GLfloat) (minValue - *dstX1) / (GLfloat) (*dstX0 - *dstX1);
+      /* chop off [0, t] part */
+      ASSERT(t >= 0.0 && t <= 1.0);
+      *dstX1 = minValue;
+      bias = (*srcX0 < *srcX1) ? 0.5 : -0.5;
+      *srcX1 = *srcX1 + (GLint) (t * (*srcX0 - *srcX1) + bias);
+   }
+}
+
+
+/**
+ * Do clipping of blit src/dest rectangles.
+ * The dest rect is clipped against both the buffer bounds and scissor bounds.
+ * The src rect is just clipped against the buffer bounds.
+ *
+ * When either the src or dest rect is clipped, the other is also clipped
+ * proportionately!
+ *
+ * Note that X0 need not be less than X1 (same for Y) for either the source
+ * and dest rects.  That makes the clipping a little trickier.
+ *
+ * \return GL_TRUE if anything is left to draw, GL_FALSE if totally clipped
+ */
+GLboolean
+_mesa_clip_blit(GLcontext *ctx,
+                GLint *srcX0, GLint *srcY0, GLint *srcX1, GLint *srcY1,
+                GLint *dstX0, GLint *dstY0, GLint *dstX1, GLint *dstY1)
+{
+   const GLint srcXmin = 0;
+   const GLint srcXmax = ctx->ReadBuffer->Width;
+   const GLint srcYmin = 0;
+   const GLint srcYmax = ctx->ReadBuffer->Height;
+
+   /* these include scissor bounds */
+   const GLint dstXmin = ctx->DrawBuffer->_Xmin;
+   const GLint dstXmax = ctx->DrawBuffer->_Xmax;
+   const GLint dstYmin = ctx->DrawBuffer->_Ymin;
+   const GLint dstYmax = ctx->DrawBuffer->_Ymax;
+
+   /*
+   printf("PreClipX:  src: %d .. %d  dst: %d .. %d\n",
+          *srcX0, *srcX1, *dstX0, *dstX1);
+   printf("PreClipY:  src: %d .. %d  dst: %d .. %d\n",
+          *srcY0, *srcY1, *dstY0, *dstY1);
+   */
+
+   /* trivial rejection tests */
+   if (*dstX0 == *dstX1)
+      return GL_FALSE; /* no width */
+   if (*dstX0 <= dstXmin && *dstX1 <= dstXmin)
+      return GL_FALSE; /* totally out (left) of bounds */
+   if (*dstX0 >= dstXmax && *dstX1 >= dstXmax)
+      return GL_FALSE; /* totally out (right) of bounds */
+
+   if (*dstY0 == *dstY1)
+      return GL_FALSE;
+   if (*dstY0 <= dstYmin && *dstY1 <= dstYmin)
+      return GL_FALSE;
+   if (*dstY0 >= dstYmax && *dstY1 >= dstYmax)
+      return GL_FALSE;
+
+   if (*srcX0 == *srcX1)
+      return GL_FALSE;
+   if (*srcX0 <= srcXmin && *srcX1 <= srcXmin)
+      return GL_FALSE;
+   if (*srcX0 >= srcXmax && *srcX1 >= srcXmax)
+      return GL_FALSE;
+
+   if (*srcY0 == *srcY1)
+      return GL_FALSE;
+   if (*srcY0 <= srcYmin && *srcY1 <= srcYmin)
+      return GL_FALSE;
+   if (*srcY0 >= srcYmax && *srcY1 >= srcYmax)
+      return GL_FALSE;
+
+   /*
+    * dest clip
+    */
+   clip_right_or_top(srcX0, srcX1, dstX0, dstX1, dstXmax);
+   clip_right_or_top(srcY0, srcY1, dstY0, dstY1, dstYmax);
+   clip_left_or_bottom(srcX0, srcX1, dstX0, dstX1, dstXmin);
+   clip_left_or_bottom(srcY0, srcY1, dstY0, dstY1, dstYmin);
+
+   /*
+    * src clip (just swap src/dst values from above)
+    */
+   clip_right_or_top(dstX0, dstX1, srcX0, srcX1, srcXmax);
+   clip_right_or_top(dstY0, dstY1, srcY0, srcY1, srcYmax);
+   clip_left_or_bottom(dstX0, dstX1, srcX0, srcX1, srcXmin);
+   clip_left_or_bottom(dstY0, dstY1, srcY0, srcY1, srcYmin);
+
+   /*
+   printf("PostClipX: src: %d .. %d  dst: %d .. %d\n",
+          *srcX0, *srcX1, *dstX0, *dstX1);
+   printf("PostClipY: src: %d .. %d  dst: %d .. %d\n",
+          *srcY0, *srcY1, *dstY0, *dstY1);
+   */
+
+   ASSERT(*dstX0 >= dstXmin);
+   ASSERT(*dstX0 <= dstXmax);
+   ASSERT(*dstX1 >= dstXmin);
+   ASSERT(*dstX1 <= dstXmax);
+
+   ASSERT(*dstY0 >= dstYmin);
+   ASSERT(*dstY0 <= dstYmax);
+   ASSERT(*dstY1 >= dstYmin);
+   ASSERT(*dstY1 <= dstYmax);
+
+   ASSERT(*srcX0 >= srcXmin);
+   ASSERT(*srcX0 <= srcXmax);
+   ASSERT(*srcX1 >= srcXmin);
+   ASSERT(*srcX1 <= srcXmax);
+
+   ASSERT(*srcY0 >= srcYmin);
+   ASSERT(*srcY0 <= srcYmax);
+   ASSERT(*srcY1 >= srcYmin);
+   ASSERT(*srcY1 <= srcYmax);
+
+   return GL_TRUE;
+}
index b26c27e..ee17acc 100644 (file)
@@ -291,4 +291,10 @@ _mesa_clip_to_region(GLint xmin, GLint ymin,
                      GLint *x, GLint *y,
                      GLsizei *width, GLsizei *height );
 
+extern GLboolean
+_mesa_clip_blit(GLcontext *ctx,
+                GLint *srcX0, GLint *srcY0, GLint *srcX1, GLint *srcY1,
+                GLint *dstX0, GLint *dstY0, GLint *dstX1, GLint *dstY1);
+
+
 #endif
index 2852623..c741940 100644 (file)
@@ -69,34 +69,107 @@ st_BlitFramebuffer(GLcontext *ctx,
                    GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
                    GLbitfield mask, GLenum filter)
 {
+   const GLbitfield depthStencil = (GL_DEPTH_BUFFER_BIT |
+                                    GL_STENCIL_BUFFER_BIT);
    struct st_context *st = ctx->st;
-
    const uint pFilter = ((filter == GL_NEAREST)
                          ? PIPE_TEX_MIPFILTER_NEAREST
                          : PIPE_TEX_MIPFILTER_LINEAR);
+   struct gl_framebuffer *readFB = ctx->ReadBuffer;
+   struct gl_framebuffer *drawFB = ctx->DrawBuffer;
+
+   if (!_mesa_clip_blit(ctx, &srcX0, &srcY0, &srcX1, &srcY1,
+                        &dstX0, &dstY0, &dstX1, &dstY1)) {
+      return; /* nothing to draw/blit */
+   }
+
+   if (st_fb_orientation(drawFB) == Y_0_TOP) {
+      /* invert Y for dest */
+      dstY0 = drawFB->Height - dstY0;
+      dstY1 = drawFB->Height - dstY1;
+   }
+
+   if (st_fb_orientation(readFB) == Y_0_TOP) {
+      /* invert Y for src */
+      srcY0 = readFB->Height - srcY0;
+      srcY1 = readFB->Height - srcY1;
+   }
+
+   if (srcY0 > srcY1 && dstY0 > dstY1) {
+      /* Both src and dst are upside down.  Swap Y to make it
+       * right-side up to increase odds of using a fast path.
+       * Recall that all Gallium raster coords have Y=0=top.
+       */
+      GLint tmp;
+      tmp = srcY0;
+      srcY0 = srcY1;
+      srcY1 = tmp;
+      tmp = dstY0;
+      dstY0 = dstY1;
+      dstY1 = tmp;
+   }
 
    if (mask & GL_COLOR_BUFFER_BIT) {
       struct st_renderbuffer *srcRb = 
-         st_renderbuffer(ctx->ReadBuffer->_ColorReadBuffer);
+         st_renderbuffer(readFB->_ColorReadBuffer);
       struct st_renderbuffer *dstRb = 
-         st_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]);
+         st_renderbuffer(drawFB->_ColorDrawBuffers[0]);
       struct pipe_surface *srcSurf = srcRb->surface;
       struct pipe_surface *dstSurf = dstRb->surface;
 
-      if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
-         /* invert Y */
-         srcY0 = srcRb->Base.Height - srcY0;
-         srcY1 = srcRb->Base.Height - srcY1;
-
-         dstY0 = dstRb->Base.Height - dstY0;
-         dstY1 = dstRb->Base.Height - dstY1;
-      }
-
       util_blit_pixels(st->blit,
                        srcSurf, srcX0, srcY0, srcX1, srcY1,
                        dstSurf, dstX0, dstY0, dstX1, dstY1,
                        0.0, pFilter);
+   }
 
+   if (mask & depthStencil) {
+      /* depth and/or stencil blit */
+
+      /* get src/dst depth surfaces */
+      struct st_renderbuffer *srcDepthRb = 
+         st_renderbuffer(readFB->Attachment[BUFFER_DEPTH].Renderbuffer);
+      struct st_renderbuffer *dstDepthRb = 
+         st_renderbuffer(drawFB->Attachment[BUFFER_DEPTH].Renderbuffer);
+      struct pipe_surface *srcDepthSurf =
+         srcDepthRb ? srcDepthRb->surface : NULL;
+      struct pipe_surface *dstDepthSurf =
+         dstDepthRb ? dstDepthRb->surface : NULL;
+
+      /* get src/dst stencil surfaces */
+      struct st_renderbuffer *srcStencilRb = 
+         st_renderbuffer(readFB->Attachment[BUFFER_STENCIL].Renderbuffer);
+      struct st_renderbuffer *dstStencilRb = 
+         st_renderbuffer(drawFB->Attachment[BUFFER_STENCIL].Renderbuffer);
+      struct pipe_surface *srcStencilSurf =
+         srcStencilRb ? srcStencilRb->surface : NULL;
+      struct pipe_surface *dstStencilSurf =
+         dstStencilRb ? dstStencilRb->surface : NULL;
+
+      if ((mask & depthStencil) == depthStencil &&
+          srcDepthSurf == srcStencilSurf &&
+          dstDepthSurf == dstStencilSurf) {
+         /* Blitting depth and stencil values between combined
+          * depth/stencil buffers.  This is the ideal case for such buffers.
+          */
+         util_blit_pixels(st->blit,
+                          srcDepthSurf, srcX0, srcY0, srcX1, srcY1,
+                          dstDepthSurf, dstX0, dstY0, dstX1, dstY1,
+                          0.0, pFilter);
+      }
+      else {
+         /* blitting depth and stencil separately */
+
+         if (mask & GL_DEPTH_BUFFER_BIT) {
+            /* blit Z only */
+            _mesa_problem(ctx, "st_BlitFramebuffer(DEPTH) not completed");
+         }
+
+         if (mask & GL_STENCIL_BUFFER_BIT) {
+            /* blit stencil only */
+            _mesa_problem(ctx, "st_BlitFramebuffer(STENCIL) not completed");
+         }
+      }
    }
 }
 
index 8a958e8..3f835d3 100644 (file)
@@ -233,7 +233,9 @@ void st_init_extensions(struct st_context *st)
 
    if (screen->get_param(screen, PIPE_CAP_POINT_SPRITE)) {
       ctx->Extensions.ARB_point_sprite = GL_TRUE;
-      ctx->Extensions.NV_point_sprite = GL_TRUE;
+      /* GL_NV_point_sprite is not supported by gallium because we don't
+       * support the GL_POINT_SPRITE_R_MODE_NV option.
+       */
    }
 
    if (screen->get_param(screen, PIPE_CAP_OCCLUSION_QUERY)) {
index 0e32cb8..4a95c22 100644 (file)
@@ -24,6 +24,7 @@
 
 
 #include "main/glheader.h"
+#include "main/image.h"
 #include "main/macros.h"
 #include "s_context.h"
 
@@ -551,184 +552,6 @@ simple_blit(GLcontext *ctx,
 
 
 /**
- * Clip dst coords against Xmax (or Ymax).
- */
-static INLINE void
-clip_right_or_top(GLint *srcX0, GLint *srcX1,
-                  GLint *dstX0, GLint *dstX1,
-                  GLint maxValue)
-{
-   GLfloat t, bias;
-
-   if (*dstX1 > maxValue) {
-      /* X1 outside right edge */
-      ASSERT(*dstX0 < maxValue); /* X0 should be inside right edge */
-      t = (GLfloat) (maxValue - *dstX0) / (GLfloat) (*dstX1 - *dstX0);
-      /* chop off [t, 1] part */
-      ASSERT(t >= 0.0 && t <= 1.0);
-      *dstX1 = maxValue;
-      bias = (*srcX0 < *srcX1) ? 0.5 : -0.5;
-      *srcX1 = *srcX0 + (GLint) (t * (*srcX1 - *srcX0) + bias);
-   }
-   else if (*dstX0 > maxValue) {
-      /* X0 outside right edge */
-      ASSERT(*dstX1 < maxValue); /* X1 should be inside right edge */
-      t = (GLfloat) (maxValue - *dstX1) / (GLfloat) (*dstX0 - *dstX1);
-      /* chop off [t, 1] part */
-      ASSERT(t >= 0.0 && t <= 1.0);
-      *dstX0 = maxValue;
-      bias = (*srcX0 < *srcX1) ? -0.5 : 0.5;
-      *srcX0 = *srcX1 + (GLint) (t * (*srcX0 - *srcX1) + bias);
-   }
-}
-
-
-/**
- * Clip dst coords against Xmin (or Ymin).
- */
-static INLINE void
-clip_left_or_bottom(GLint *srcX0, GLint *srcX1,
-                    GLint *dstX0, GLint *dstX1,
-                    GLint minValue)
-{
-   GLfloat t, bias;
-
-   if (*dstX0 < minValue) {
-      /* X0 outside left edge */
-      ASSERT(*dstX1 > minValue); /* X1 should be inside left edge */
-      t = (GLfloat) (minValue - *dstX0) / (GLfloat) (*dstX1 - *dstX0);
-      /* chop off [0, t] part */
-      ASSERT(t >= 0.0 && t <= 1.0);
-      *dstX0 = minValue;
-      bias = (*srcX0 < *srcX1) ? 0.5 : -0.5; /* flipped??? */
-      *srcX0 = *srcX0 + (GLint) (t * (*srcX1 - *srcX0) + bias);
-   }
-   else if (*dstX1 < minValue) {
-      /* X1 outside left edge */
-      ASSERT(*dstX0 > minValue); /* X0 should be inside left edge */
-      t = (GLfloat) (minValue - *dstX1) / (GLfloat) (*dstX0 - *dstX1);
-      /* chop off [0, t] part */
-      ASSERT(t >= 0.0 && t <= 1.0);
-      *dstX1 = minValue;
-      bias = (*srcX0 < *srcX1) ? 0.5 : -0.5;
-      *srcX1 = *srcX1 + (GLint) (t * (*srcX0 - *srcX1) + bias);
-   }
-}
-
-
-/**
- * Do clipping of blit src/dest rectangles.
- * The dest rect is clipped against both the buffer bounds and scissor bounds.
- * The src rect is just clipped against the buffer bounds.
- *
- * When either the src or dest rect is clipped, the other is also clipped
- * proportionately!
- *
- * Note that X0 need not be less than X1 (same for Y) for either the source
- * and dest rects.  That makes the clipping a little trickier.
- *
- * \return GL_TRUE if anything is left to draw, GL_FALSE if totally clipped
- */
-static GLboolean
-clip_blit(GLcontext *ctx,
-          GLint *srcX0, GLint *srcY0, GLint *srcX1, GLint *srcY1,
-          GLint *dstX0, GLint *dstY0, GLint *dstX1, GLint *dstY1)
-{
-   const GLint srcXmin = 0;
-   const GLint srcXmax = ctx->ReadBuffer->Width;
-   const GLint srcYmin = 0;
-   const GLint srcYmax = ctx->ReadBuffer->Height;
-
-   /* these include scissor bounds */
-   const GLint dstXmin = ctx->DrawBuffer->_Xmin;
-   const GLint dstXmax = ctx->DrawBuffer->_Xmax;
-   const GLint dstYmin = ctx->DrawBuffer->_Ymin;
-   const GLint dstYmax = ctx->DrawBuffer->_Ymax;
-
-   /*
-   printf("PreClipX:  src: %d .. %d  dst: %d .. %d\n",
-          *srcX0, *srcX1, *dstX0, *dstX1);
-   printf("PreClipY:  src: %d .. %d  dst: %d .. %d\n",
-          *srcY0, *srcY1, *dstY0, *dstY1);
-   */
-
-   /* trivial rejection tests */
-   if (*dstX0 == *dstX1)
-      return GL_FALSE; /* no width */
-   if (*dstX0 <= dstXmin && *dstX1 <= dstXmin)
-      return GL_FALSE; /* totally out (left) of bounds */
-   if (*dstX0 >= dstXmax && *dstX1 >= dstXmax)
-      return GL_FALSE; /* totally out (right) of bounds */
-
-   if (*dstY0 == *dstY1)
-      return GL_FALSE;
-   if (*dstY0 <= dstYmin && *dstY1 <= dstYmin)
-      return GL_FALSE;
-   if (*dstY0 >= dstYmax && *dstY1 >= dstYmax)
-      return GL_FALSE;
-
-   if (*srcX0 == *srcX1)
-      return GL_FALSE;
-   if (*srcX0 <= srcXmin && *srcX1 <= srcXmin)
-      return GL_FALSE;
-   if (*srcX0 >= srcXmax && *srcX1 >= srcXmax)
-      return GL_FALSE;
-
-   if (*srcY0 == *srcY1)
-      return GL_FALSE;
-   if (*srcY0 <= srcYmin && *srcY1 <= srcYmin)
-      return GL_FALSE;
-   if (*srcY0 >= srcYmax && *srcY1 >= srcYmax)
-      return GL_FALSE;
-
-   /*
-    * dest clip
-    */
-   clip_right_or_top(srcX0, srcX1, dstX0, dstX1, dstXmax);
-   clip_right_or_top(srcY0, srcY1, dstY0, dstY1, dstYmax);
-   clip_left_or_bottom(srcX0, srcX1, dstX0, dstX1, dstXmin);
-   clip_left_or_bottom(srcY0, srcY1, dstY0, dstY1, dstYmin);
-
-   /*
-    * src clip (just swap src/dst values from above)
-    */
-   clip_right_or_top(dstX0, dstX1, srcX0, srcX1, srcXmax);
-   clip_right_or_top(dstY0, dstY1, srcY0, srcY1, srcYmax);
-   clip_left_or_bottom(dstX0, dstX1, srcX0, srcX1, srcXmin);
-   clip_left_or_bottom(dstY0, dstY1, srcY0, srcY1, srcYmin);
-
-   /*
-   printf("PostClipX: src: %d .. %d  dst: %d .. %d\n",
-          *srcX0, *srcX1, *dstX0, *dstX1);
-   printf("PostClipY: src: %d .. %d  dst: %d .. %d\n",
-          *srcY0, *srcY1, *dstY0, *dstY1);
-   */
-
-   ASSERT(*dstX0 >= dstXmin);
-   ASSERT(*dstX0 <= dstXmax);
-   ASSERT(*dstX1 >= dstXmin);
-   ASSERT(*dstX1 <= dstXmax);
-
-   ASSERT(*dstY0 >= dstYmin);
-   ASSERT(*dstY0 <= dstYmax);
-   ASSERT(*dstY1 >= dstYmin);
-   ASSERT(*dstY1 <= dstYmax);
-
-   ASSERT(*srcX0 >= srcXmin);
-   ASSERT(*srcX0 <= srcXmax);
-   ASSERT(*srcX1 >= srcXmin);
-   ASSERT(*srcX1 <= srcXmax);
-
-   ASSERT(*srcY0 >= srcYmin);
-   ASSERT(*srcY0 <= srcYmax);
-   ASSERT(*srcY1 >= srcYmin);
-   ASSERT(*srcY1 <= srcYmax);
-
-   return GL_TRUE;
-}
-
-
-/**
  * Software fallback for glBlitFramebufferEXT().
  */
 void
@@ -747,8 +570,8 @@ _swrast_BlitFramebuffer(GLcontext *ctx,
    if (!ctx->DrawBuffer->_NumColorDrawBuffers)
       return;
 
-   if (!clip_blit(ctx, &srcX0, &srcY0, &srcX1, &srcY1,
-                  &dstX0, &dstY0, &dstX1, &dstY1)) {
+   if (!_mesa_clip_blit(ctx, &srcX0, &srcY0, &srcX1, &srcY1,
+                        &dstX0, &dstY0, &dstX1, &dstY1)) {
       return;
    }