intel: Remove a gratuitous MI_FLUSH after clearing with a blit.
[mesa.git] / src / mesa / drivers / dri / intel / intel_pixel_bitmap.c
index 896351989318510fff53f64ce260d8dbb40dc0b2..1db7f5594e9dd3849c242621071cce19692d748b 100644 (file)
 #include "main/mtypes.h"
 #include "main/macros.h"
 #include "main/bufferobj.h"
+#include "main/pixelstore.h"
+#include "main/state.h"
+#include "main/teximage.h"
+#include "main/texenv.h"
+#include "main/texobj.h"
+#include "main/texstate.h"
+#include "main/texparam.h"
+#include "main/varray.h"
+#include "main/attrib.h"
+#include "main/enable.h"
+#include "shader/arbprogram.h"
+#include "glapi/dispatch.h"
 #include "swrast/swrast.h"
 
 #include "intel_screen.h"
@@ -86,6 +98,11 @@ static GLboolean test_bit( const GLubyte *src,
    return (src[bit/8] & (1<<(bit % 8))) ? 1 : 0;
 }
 
+static GLboolean test_msb_bit(const GLubyte *src, GLuint bit)
+{
+   return (src[bit/8] & (1<<(7 - (bit % 8)))) ? 1 : 0;
+}
+
 static void set_bit( GLubyte *dest,
                          GLuint bit )
 {
@@ -149,8 +166,18 @@ static GLuint get_bitmap_rect(GLsizei width, GLsizei height,
    return count;
 }
 
-
-
+/**
+ * Returns the low Y value of the vertical range given, flipped according to
+ * whether the framebuffer is or not.
+ */
+static inline int
+y_flip(struct gl_framebuffer *fb, int y, int height)
+{
+   if (fb->Name != 0)
+      return y;
+   else
+      return fb->Height - y - height;
+}
 
 /*
  * Render a bitmap.
@@ -164,9 +191,26 @@ do_blit_bitmap( GLcontext *ctx,
 {
    struct intel_context *intel = intel_context(ctx);
    struct intel_region *dst = intel_drawbuf_region(intel);
+   struct gl_framebuffer *fb = ctx->DrawBuffer;
    GLfloat tmpColor[4];
    GLubyte ubcolor[4];
    GLuint color8888, color565;
+   unsigned int num_cliprects;
+   drm_clip_rect_t *cliprects;
+   int x_off, y_off;
+   GLsizei bitmap_width = width;
+   GLsizei bitmap_height = height;
+
+   /* Update draw buffer bounds */
+   _mesa_update_state(ctx);
+
+   if (ctx->Depth.Test) {
+      /* The blit path produces incorrect results when depth testing is on.
+       * It seems the blit Z coord is always 1.0 (the far plane) so fragments
+       * will likely be obscured by other, closer geometry.
+       */
+      return GL_FALSE;
+   }
 
    if (!dst)
        return GL_FALSE;
@@ -191,68 +235,43 @@ do_blit_bitmap( GLcontext *ctx,
    color8888 = INTEL_PACKCOLOR8888(ubcolor[0], ubcolor[1], ubcolor[2], ubcolor[3]);
    color565 = INTEL_PACKCOLOR565(ubcolor[0], ubcolor[1], ubcolor[2]);
 
-   /* Does zoom apply to bitmaps?
-    */
-   if (!intel_check_blit_fragment_ops(ctx, tmpColor[3] == 1.0F) ||
-       ctx->Pixel.ZoomX != 1.0F || 
-       ctx->Pixel.ZoomY != 1.0F)
+   if (!intel_check_blit_fragment_ops(ctx, tmpColor[3] == 1.0F))
       return GL_FALSE;
 
    LOCK_HARDWARE(intel);
 
-   if (intel->driDrawable->numClipRects) {
-      __DRIdrawablePrivate *dPriv = intel->driDrawable;
-      drm_clip_rect_t *box = dPriv->pClipRects;
-      drm_clip_rect_t dest_rect;
-      GLint nbox = dPriv->numClipRects;
-      GLint srcx = 0, srcy = 0;
-      GLint orig_screen_x1, orig_screen_y2;
+   intel_get_cliprects(intel, &cliprects, &num_cliprects, &x_off, &y_off);
+   if (num_cliprects != 0) {
       GLuint i;
+      GLint orig_dstx = dstx;
+      GLint orig_dsty = dsty;
 
-
-      orig_screen_x1 = dPriv->x + dstx;
-      orig_screen_y2 = dPriv->y + (dPriv->h - dsty);
-
-      /* Do scissoring in GL coordinates:
-       */
-      if (ctx->Scissor.Enabled)
-      {
-        GLint x = ctx->Scissor.X;
-        GLint y = ctx->Scissor.Y;
-        GLuint w = ctx->Scissor.Width;
-        GLuint h = ctx->Scissor.Height;
-
-         if (!_mesa_clip_to_region(x, y, x+w-1, y+h-1, &dstx, &dsty, &width, &height))
+      /* Clip to buffer bounds and scissor. */
+      if (!_mesa_clip_to_region(fb->_Xmin, fb->_Ymin,
+                               fb->_Xmax, fb->_Ymax,
+                               &dstx, &dsty, &width, &height))
             goto out;
-      }
-
-      /* Convert from GL to hardware coordinates:
-       */
-      dsty = dPriv->y + (dPriv->h - dsty - height);  
-      dstx = dPriv->x + dstx;
 
-      dest_rect.x1 = dstx < 0 ? 0 : dstx;
-      dest_rect.y1 = dsty < 0 ? 0 : dsty;
-      dest_rect.x2 = dstx + width < 0 ? 0 : dstx + width;
-      dest_rect.y2 = dsty + height < 0 ? 0 : dsty + height;
+      dstx = x_off + dstx;
+      dsty = y_off + y_flip(fb, dsty, height);
 
-      for (i = 0; i < nbox; i++) {
-         drm_clip_rect_t rect;
-        int box_w, box_h;
+      for (i = 0; i < num_cliprects; i++) {
+        int box_x, box_y, box_w, box_h;
         GLint px, py;
         GLuint stipple[32];  
 
-         if (!intel_intersect_cliprects(&rect, &dest_rect, &box[i]))
-            continue;
-
-        /* Now go back to GL coordinates to figure out what subset of
-         * the bitmap we are uploading for this cliprect:
-         */
-        box_w = rect.x2 - rect.x1;
-        box_h = rect.y2 - rect.y1;
-        srcx = rect.x1 - orig_screen_x1;
-        srcy = orig_screen_y2 - rect.y2;
+        box_x = dstx;
+        box_y = dsty;
+        box_w = width;
+        box_h = height;
 
+        /* Clip to drawable cliprect */
+         if (!_mesa_clip_to_region(cliprects[i].x1,
+                                  cliprects[i].y1,
+                                  cliprects[i].x2,
+                                  cliprects[i].y2,
+                                  &box_x, &box_y, &box_w, &box_h))
+           continue;
 
 #define DY 32
 #define DX 32
@@ -273,13 +292,19 @@ do_blit_bitmap( GLcontext *ctx,
 
               /* May need to adjust this when padding has been introduced in
                * sz above:
+               *
+               * Have to translate destination coordinates back into source
+               * coordinates.
                */
-              if (get_bitmap_rect(width, height, unpack, 
+              if (get_bitmap_rect(bitmap_width, bitmap_height, unpack,
                                   bitmap,
-                                  srcx + px, srcy + py, w, h,
+                                  -orig_dstx + (box_x + px - x_off),
+                                  -orig_dsty + y_flip(fb,
+                                                      box_y + py - y_off, h),
+                                  w, h,
                                   (GLubyte *)stipple,
                                   8,
-                                  GL_TRUE) == 0)
+                                  fb->Name == 0 ? GL_TRUE : GL_FALSE) == 0)
                  continue;
 
               /* 
@@ -293,8 +318,8 @@ do_blit_bitmap( GLcontext *ctx,
                                                  dst->buffer,
                                                  0,
                                                  dst->tiling,
-                                                 rect.x1 + px,
-                                                 rect.y2 - (py + h),
+                                                 box_x + px,
+                                                 box_y + py,
                                                  w, h,
                                                  logic_op);
            } 
@@ -304,6 +329,8 @@ do_blit_bitmap( GLcontext *ctx,
 out:
    UNLOCK_HARDWARE(intel);
 
+   if (INTEL_DEBUG & DEBUG_SYNC)
+      intel_batchbuffer_flush(intel->batch);
 
    if (unpack->BufferObj->Name) {
       /* done with PBO so unmap it now */
@@ -314,9 +341,179 @@ out:
    return GL_TRUE;
 }
 
+static GLboolean
+intel_texture_bitmap(GLcontext * ctx,
+                    GLint dst_x, GLint dst_y,
+                    GLsizei width, GLsizei height,
+                    const struct gl_pixelstore_attrib *unpack,
+                    const GLubyte *bitmap)
+{
+   struct intel_context *intel = intel_context(ctx);
+   static const char *fp =
+      "!!ARBfp1.0\n"
+      "TEMP val;\n"
+      "PARAM color=program.local[0];\n"
+      "TEX val, fragment.texcoord[0], texture[0], 2D;\n"
+      "ADD val, val.wwww, {-.5, -.5, -.5, -.5};\n"
+      "KIL val;\n"
+      "MOV result.color, color;\n"
+      "END\n";
+   GLuint texname;
+   GLfloat vertices[4][4];
+   GLfloat texcoords[4][2];
+   GLint old_active_texture;
+   GLubyte *unpacked_bitmap;
+   GLubyte *a8_bitmap;
+   int x, y;
+   GLfloat dst_z;
+
+   /* We need a fragment program for the KIL effect */
+   if (!ctx->Extensions.ARB_fragment_program ||
+       !ctx->Extensions.ARB_vertex_program) {
+      if (INTEL_DEBUG & DEBUG_FALLBACKS)
+        fprintf(stderr,
+                "glBitmap fallback: No fragment/vertex program support\n");
+      return GL_FALSE;
+   }
 
+   /* We're going to mess with texturing with no regard to existing texture
+    * state, so if there is some set up we have to bail.
+    */
+   if (ctx->Texture._EnabledUnits != 0) {
+      if (INTEL_DEBUG & DEBUG_FALLBACKS)
+        fprintf(stderr, "glBitmap fallback: texturing enabled\n");
+      return GL_FALSE;
+   }
 
+   /* Can't do textured DrawPixels with a fragment program, unless we were
+    * to generate a new program that sampled our texture and put the results
+    * in the fragment color before the user's program started.
+    */
+   if (ctx->FragmentProgram.Enabled) {
+      if (INTEL_DEBUG & DEBUG_FALLBACKS)
+        fprintf(stderr, "glBitmap fallback: fragment program enabled\n");
+      return GL_FALSE;
+   }
 
+   if (ctx->VertexProgram.Enabled) {
+      if (INTEL_DEBUG & DEBUG_FALLBACKS)
+        fprintf(stderr, "glBitmap fallback: vertex program enabled\n");
+      return GL_FALSE;
+   }
+
+   /* Check that we can load in a texture this big. */
+   if (width > (1 << (ctx->Const.MaxTextureLevels - 1)) ||
+       height > (1 << (ctx->Const.MaxTextureLevels - 1))) {
+      if (INTEL_DEBUG & DEBUG_FALLBACKS)
+        fprintf(stderr, "glBitmap fallback: bitmap too large (%dx%d)\n",
+                width, height);
+      return GL_FALSE;
+   }
+
+   /* Convert the A1 bitmap to an A8 format suitable for glTexImage */
+   if (unpack->BufferObj->Name) {
+      bitmap = map_pbo(ctx, width, height, unpack, bitmap);
+      if (bitmap == NULL)
+        return GL_TRUE;        /* even though this is an error, we're done */
+   }
+   unpacked_bitmap = _mesa_unpack_bitmap(width, height, bitmap,
+                                        unpack);
+   a8_bitmap = _mesa_calloc(width * height);
+   for (y = 0; y < height; y++) {
+      for (x = 0; x < width; x++) {
+        if (test_msb_bit(unpacked_bitmap, ALIGN(width, 8) * y + x))
+           a8_bitmap[y * width + x] = 0xff;
+      }
+   }
+   _mesa_free(unpacked_bitmap);
+   if (unpack->BufferObj->Name) {
+      /* done with PBO so unmap it now */
+      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
+                              unpack->BufferObj);
+   }
+
+   /* Save GL state before we start setting up our drawing */
+   _mesa_PushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT |
+                   GL_VIEWPORT_BIT);
+   _mesa_PushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT |
+                         GL_CLIENT_PIXEL_STORE_BIT);
+   old_active_texture = ctx->Texture.CurrentUnit;
+
+   _mesa_Disable(GL_POLYGON_STIPPLE);
+
+   /* Upload our bitmap data to an alpha texture */
+   _mesa_ActiveTextureARB(GL_TEXTURE0_ARB);
+   _mesa_Enable(GL_TEXTURE_2D);
+   _mesa_GenTextures(1, &texname);
+   _mesa_BindTexture(GL_TEXTURE_2D, texname);
+   _mesa_TexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+   _mesa_TexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+   _mesa_PixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
+   _mesa_PixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
+   _mesa_PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+   _mesa_PixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+   _mesa_PixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+   _mesa_PixelStorei(GL_UNPACK_ALIGNMENT, 1);
+   _mesa_TexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0,
+                   GL_ALPHA, GL_UNSIGNED_BYTE, a8_bitmap);
+   _mesa_free(a8_bitmap);
+
+   intel_meta_set_fragment_program(intel, &intel->meta.bitmap_fp, fp);
+   _mesa_ProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 0,
+                                    ctx->Current.RasterColor);
+   intel_meta_set_passthrough_vertex_program(intel);
+   intel_meta_set_passthrough_transform(intel);
+
+   /* convert rasterpos Z from [0,1] to NDC coord in [-1,1] */
+   dst_z = -1.0 + 2.0 * ctx->Current.RasterPos[2];
+
+   vertices[0][0] = dst_x;
+   vertices[0][1] = dst_y;
+   vertices[0][2] = dst_z;
+   vertices[0][3] = 1.0;
+   vertices[1][0] = dst_x + width;
+   vertices[1][1] = dst_y;
+   vertices[1][2] = dst_z;
+   vertices[1][3] = 1.0;
+   vertices[2][0] = dst_x + width;
+   vertices[2][1] = dst_y + height;
+   vertices[2][2] = dst_z;
+   vertices[2][3] = 1.0;
+   vertices[3][0] = dst_x;
+   vertices[3][1] = dst_y + height;
+   vertices[3][2] = dst_z;
+   vertices[3][3] = 1.0;
+
+   texcoords[0][0] = 0.0;
+   texcoords[0][1] = 0.0;
+   texcoords[1][0] = 1.0;
+   texcoords[1][1] = 0.0;
+   texcoords[2][0] = 1.0;
+   texcoords[2][1] = 1.0;
+   texcoords[3][0] = 0.0;
+   texcoords[3][1] = 1.0;
+
+   _mesa_VertexPointer(4, GL_FLOAT, 4 * sizeof(GLfloat), &vertices);
+   _mesa_ClientActiveTextureARB(GL_TEXTURE0);
+   _mesa_TexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), &texcoords);
+   _mesa_Enable(GL_VERTEX_ARRAY);
+   _mesa_Enable(GL_TEXTURE_COORD_ARRAY);
+   CALL_DrawArrays(ctx->Exec, (GL_TRIANGLE_FAN, 0, 4));
+
+   intel_meta_restore_transform(intel);
+   intel_meta_restore_fragment_program(intel);
+   intel_meta_restore_vertex_program(intel);
+
+   _mesa_PopClientAttrib();
+   _mesa_Disable(GL_TEXTURE_2D); /* asserted that it was disabled at entry */
+   _mesa_ActiveTextureARB(GL_TEXTURE0_ARB + old_active_texture);
+   _mesa_PopAttrib();
+
+   _mesa_DeleteTextures(1, &texname);
+
+   return GL_TRUE;
+}
 
 /* There are a large number of possible ways to implement bitmap on
  * this hardware, most of them have some sort of drawback.  Here are a
@@ -349,6 +546,10 @@ intelBitmap(GLcontext * ctx,
                           unpack, pixels))
       return;
 
+   if (intel_texture_bitmap(ctx, x, y, width, height,
+                           unpack, pixels))
+      return;
+
    if (INTEL_DEBUG & DEBUG_PIXEL)
       _mesa_printf("%s: fallback to swrast\n", __FUNCTION__);