i915: Use enum color_logic_ops for blits
[mesa.git] / src / mesa / drivers / dri / i915 / intel_pixel_bitmap.c
index 65bf338589e9c7d7e55a10a49cb275d9081a30e2..8dee0bea9f2115e3c37a19b566ce594368ac12b0 100644 (file)
@@ -1,6 +1,6 @@
 /**************************************************************************
  * 
- * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright 2006 VMware, Inc.
  * All Rights Reserved.
  * 
  * Permission is hereby granted, free of charge, to any person obtaining a
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
- * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  * 
  **************************************************************************/
 
-#include "glheader.h"
-#include "enums.h"
-#include "image.h"
-#include "colormac.h"
-#include "mtypes.h"
-#include "macros.h"
-#include "bufferobj.h"
+#include "main/glheader.h"
+#include "main/enums.h"
+#include "main/image.h"
+#include "main/colormac.h"
+#include "main/condrender.h"
+#include "main/mtypes.h"
+#include "main/macros.h"
+#include "main/pbo.h"
+#include "main/bufferobj.h"
+#include "main/state.h"
+#include "main/texobj.h"
+#include "main/context.h"
+#include "main/fbobject.h"
 #include "swrast/swrast.h"
+#include "drivers/common/meta.h"
 
 #include "intel_screen.h"
 #include "intel_context.h"
-#include "intel_ioctl.h"
 #include "intel_batchbuffer.h"
 #include "intel_blit.h"
+#include "intel_fbo.h"
 #include "intel_regions.h"
-#include "intel_buffer_objects.h"
-
+#include "intel_buffers.h"
+#include "intel_pixel.h"
+#include "intel_reg.h"
 
 
 #define FILE_DEBUG_FLAG DEBUG_PIXEL
@@ -54,7 +62,7 @@
  * PBO bitmaps.  I think they are probably pretty rare though - I
  * wonder if Xgl uses them?
  */
-static const GLubyte *map_pbo( GLcontext *ctx,
+static const GLubyte *map_pbo( struct gl_context *ctx,
                               GLsizei width, GLsizei height,
                               const struct gl_pixelstore_attrib *unpack,
                               const GLubyte *bitmap )
@@ -63,14 +71,15 @@ static const GLubyte *map_pbo( GLcontext *ctx,
 
    if (!_mesa_validate_pbo_access(2, unpack, width, height, 1,
                                  GL_COLOR_INDEX, GL_BITMAP,
-                                 (GLvoid *) bitmap)) {
+                                 INT_MAX, (const GLvoid *) bitmap)) {
       _mesa_error(ctx, GL_INVALID_OPERATION,"glBitmap(invalid PBO access)");
       return NULL;
    }
 
-   buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
-                                          GL_READ_ONLY_ARB,
-                                          unpack->BufferObj);
+   buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0, unpack->BufferObj->Size,
+                                               GL_MAP_READ_BIT,
+                                               unpack->BufferObj,
+                                                MAP_INTERNAL);
    if (!buf) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "glBitmap(PBO is mapped)");
       return NULL;
@@ -79,25 +88,18 @@ static const GLubyte *map_pbo( GLcontext *ctx,
    return ADD_POINTERS(buf, bitmap);
 }
 
-static GLboolean test_bit( const GLubyte *src,
-                           GLuint bit )
+static bool test_bit( const GLubyte *src, GLuint bit )
 {
    return (src[bit/8] & (1<<(bit % 8))) ? 1 : 0;
 }
 
-static void set_bit( GLubyte *dest,
-                         GLuint bit )
+static void set_bit( GLubyte *dest, GLuint bit )
 {
    dest[bit/8] |= 1 << (bit % 8);
 }
 
-static int align(int x, int align)
-{
-   return (x + align - 1) & ~(align - 1);
-}
-
 /* Extract a rectangle's worth of data from the bitmap.  Called
- * per-cliprect.
+ * per chunk of HW-sized bitmap.
  */
 static GLuint get_bitmap_rect(GLsizei width, GLsizei height,
                              const struct gl_pixelstore_attrib *unpack,
@@ -106,7 +108,7 @@ static GLuint get_bitmap_rect(GLsizei width, GLsizei height,
                              GLuint w, GLuint h,
                              GLubyte *dest,
                              GLuint row_align,
-                             GLboolean invert)
+                             bool invert)
 {
    GLuint src_offset = (x + unpack->SkipPixels) & 0x7;
    GLuint mask = unpack->LsbFirst ? 0 : 7;
@@ -116,9 +118,8 @@ static GLuint get_bitmap_rect(GLsizei width, GLsizei height,
    GLint incr;
    GLuint count = 0;
 
-   if (INTEL_DEBUG & DEBUG_PIXEL)
-      _mesa_printf("%s %d,%d %dx%d bitmap %dx%d skip %d src_offset %d mask %d\n",
-                  __FUNCTION__, x,y,w,h,width,height,unpack->SkipPixels, src_offset, mask);
+   DBG("%s %d,%d %dx%d bitmap %dx%d skip %d src_offset %d mask %d\n",
+       __func__, x,y,w,h,width,height,unpack->SkipPixels, src_offset, mask);
 
    if (invert) {
       first = h-1;
@@ -147,169 +148,177 @@ static GLuint get_bitmap_rect(GLsizei width, GLsizei height,
       }
 
       if (row_align)
-        bit = (bit + row_align - 1) & ~(row_align - 1);
+        bit = ALIGN(bit, row_align);
    }
 
    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 (_mesa_is_user_fbo(fb))
+      return y;
+   else
+      return fb->Height - y - height;
+}
 
 /*
  * Render a bitmap.
  */
-static GLboolean
-do_blit_bitmap( GLcontext *ctx, 
+static bool
+do_blit_bitmap( struct gl_context *ctx, 
                GLint dstx, GLint dsty,
                GLsizei width, GLsizei height,
                const struct gl_pixelstore_attrib *unpack,
                const GLubyte *bitmap )
 {
    struct intel_context *intel = intel_context(ctx);
-   struct intel_region *dst = intel_drawbuf_region(intel);
-   
-   union {
-      GLuint ui;
-      GLubyte ub[4];
-   } color;
-
-
-   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 */
+   struct gl_framebuffer *fb = ctx->DrawBuffer;
+   struct intel_renderbuffer *irb;
+   GLfloat tmpColor[4];
+   GLubyte ubcolor[4];
+   GLuint color;
+   GLsizei bitmap_width = width;
+   GLsizei bitmap_height = height;
+   GLint px, py;
+   GLuint stipple[32];
+   GLint orig_dstx = dstx;
+   GLint orig_dsty = dsty;
+
+   /* 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 false;
    }
 
-   UNCLAMPED_FLOAT_TO_CHAN(color.ub[0], ctx->Current.RasterColor[2]);
-   UNCLAMPED_FLOAT_TO_CHAN(color.ub[1], ctx->Current.RasterColor[1]);
-   UNCLAMPED_FLOAT_TO_CHAN(color.ub[2], ctx->Current.RasterColor[0]);
-   UNCLAMPED_FLOAT_TO_CHAN(color.ub[3], ctx->Current.RasterColor[3]);
-
-   /* Does zoom apply to bitmaps?
-    */
-   if (!intel_check_blit_fragment_ops(ctx) ||
-       ctx->Pixel.ZoomX != 1.0F || 
-       ctx->Pixel.ZoomY != 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;
-      GLuint i;
+   intel_prepare_render(intel);
 
+   if (fb->_NumColorDrawBuffers != 1) {
+      perf_debug("accelerated glBitmap() only supports rendering to a "
+                 "single color buffer\n");
+      return false;
+   }
 
-      orig_screen_x1 = dPriv->x + dstx;
-      orig_screen_y2 = dPriv->y + (dPriv->h - dsty);
+   irb = intel_renderbuffer(fb->_ColorDrawBuffers[0]);
 
-      /* Do scissoring in GL coordinates:
-       */
-x      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))
-            goto out;
-      }
+   if (_mesa_is_bufferobj(unpack->BufferObj)) {
+      bitmap = map_pbo(ctx, width, height, unpack, bitmap);
+      if (bitmap == NULL)
+        return true;   /* even though this is an error, we're done */
+   }
 
-      /* Convert from GL to hardware coordinates:
-       */
-      dsty = dPriv->y + (dPriv->h - dsty - height);  
-      dstx = dPriv->x + dstx;
+   COPY_4V(tmpColor, ctx->Current.RasterColor);
 
-      dest_rect.x1 = dstx;
-      dest_rect.y1 = dsty;
-      dest_rect.x2 = dstx + width;
-      dest_rect.y2 = dsty + height;
+   if (_mesa_need_secondary_color(ctx)) {
+       ADD_3V(tmpColor, tmpColor, ctx->Current.RasterSecondaryColor);
+   }
 
-      for (i = 0; i < nbox; i++) {
-         drm_clip_rect_t rect;
-        int box_w, box_h;
-        GLint px, py;
-        GLuint stipple[32];  
+   UNCLAMPED_FLOAT_TO_UBYTE(ubcolor[0], tmpColor[0]);
+   UNCLAMPED_FLOAT_TO_UBYTE(ubcolor[1], tmpColor[1]);
+   UNCLAMPED_FLOAT_TO_UBYTE(ubcolor[2], tmpColor[2]);
+   UNCLAMPED_FLOAT_TO_UBYTE(ubcolor[3], tmpColor[3]);
+
+   switch (irb->mt->format) {
+   case MESA_FORMAT_B8G8R8A8_UNORM:
+   case MESA_FORMAT_B8G8R8X8_UNORM:
+      color = PACK_COLOR_8888(ubcolor[3], ubcolor[0], ubcolor[1], ubcolor[2]);
+      break;
+   case MESA_FORMAT_B5G6R5_UNORM:
+      color = PACK_COLOR_565(ubcolor[0], ubcolor[1], ubcolor[2]);
+      break;
+   default:
+      perf_debug("Unsupported format %s in accelerated glBitmap()\n",
+                 _mesa_get_format_name(irb->mt->format));
+      return false;
+   }
 
-         if (!intel_intersect_cliprects(&rect, &dest_rect, &box[i]))
-            continue;
+   if (!intel_check_blit_fragment_ops(ctx, tmpColor[3] == 1.0F))
+      return false;
 
-        /* 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;
+   /* 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;
 
+   dsty = y_flip(fb, dsty, height);
 
 #define DY 32
 #define DX 32
 
-        /* Then, finally, chop it all into chunks that can be
-         * digested by hardware:
+   /* Chop it all into chunks that can be digested by hardware: */
+   for (py = 0; py < height; py += DY) {
+      for (px = 0; px < width; px += DX) {
+        int h = MIN2(DY, height - py);
+        int w = MIN2(DX, width - px);
+        GLuint sz = ALIGN(ALIGN(w,8) * h, 64)/8;
+         const enum gl_logicop_mode logic_op = ctx->Color.ColorLogicOpEnabled ?
+            ctx->Color._LogicOp : COLOR_LOGICOP_COPY;
+
+        assert(sz <= sizeof(stipple));
+        memset(stipple, 0, sz);
+
+        /* May need to adjust this when padding has been introduced in
+         * sz above:
+         *
+         * Have to translate destination coordinates back into source
+         * coordinates.
          */
-        for (py = 0; py < box_h; py += DY) { 
-           for (px = 0; px < box_w; px += DX) { 
-              int h = MIN2(DY, box_h - py);
-              int w = MIN2(DX, box_w - px); 
-              GLuint sz = align(align(w,8) * h, 64)/8;
-           
-              assert(sz <= sizeof(stipple));
-              memset(stipple, 0, sz);
-
-              /* May need to adjust this when padding has been introduced in
-               * sz above:
-               */
-              if (get_bitmap_rect(width, height, unpack, 
-                                  bitmap,
-                                  srcx + px, srcy + py, w, h,
-                                  (GLubyte *)stipple,
-                                  8,
-                                  GL_TRUE) == 0)
-                 continue;
-
-              /* 
-               */
-              intelEmitImmediateColorExpandBlit( intel,
-                                                 dst->cpp,
-                                                 (GLubyte *)stipple, 
-                                                 sz,
-                                                 color.ui,
-                                                 dst->pitch,
-                                                 dst->buffer,
-                                                 0,
-                                                 dst->tiled,
-                                                 rect.x1 + px,
-                                                 rect.y2 - (py + h),
-                                                 w, h);
-           } 
-        } 
+         int count = get_bitmap_rect(bitmap_width, bitmap_height, unpack,
+                                     bitmap,
+                                     -orig_dstx + (dstx + px),
+                                     -orig_dsty + y_flip(fb, dsty + py, h),
+                                     w, h,
+                                     (GLubyte *)stipple,
+                                     8,
+                                     _mesa_is_winsys_fbo(fb));
+         if (count == 0)
+           continue;
+
+        if (!intelEmitImmediateColorExpandBlit(intel,
+                                               irb->mt->cpp,
+                                               (GLubyte *)stipple,
+                                               sz,
+                                               color,
+                                               irb->mt->region->pitch,
+                                               irb->mt->region->bo,
+                                               0,
+                                               irb->mt->region->tiling,
+                                               dstx + px,
+                                               dsty + py,
+                                               w, h,
+                                               logic_op)) {
+           return false;
+        }
+
+         if (ctx->Query.CurrentOcclusionObject)
+            ctx->Query.CurrentOcclusionObject->Result += count;
       }
-      intel->need_flush = GL_TRUE;
-   out:
-      intel_batchbuffer_flush(intel->batch);
    }
-   UNLOCK_HARDWARE(intel);
+out:
 
+   if (unlikely(INTEL_DEBUG & DEBUG_SYNC))
+      intel_batchbuffer_flush(intel);
 
-   if (unpack->BufferObj->Name) {
+   if (_mesa_is_bufferobj(unpack->BufferObj)) {
       /* done with PBO so unmap it now */
-      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
-                              unpack->BufferObj);
+      ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj, MAP_INTERNAL);
    }
 
-   return GL_TRUE;
-}
-
-
+   intel_check_front_buffer_rendering(intel);
 
+   return true;
+}
 
 
 /* There are a large number of possible ways to implement bitmap on
@@ -333,18 +342,18 @@ x      if (ctx->Scissor.Enabled)
  *    - Chop bitmap up into 32x32 squares and render w/polygon stipple.
  */
 void
-intelBitmap(GLcontext * ctx,
+intelBitmap(struct gl_context * ctx,
            GLint x, GLint y,
            GLsizei width, GLsizei height,
            const struct gl_pixelstore_attrib *unpack,
            const GLubyte * pixels)
 {
+   if (!_mesa_check_conditional_render(ctx))
+      return;
+
    if (do_blit_bitmap(ctx, x, y, width, height,
                           unpack, pixels))
       return;
 
-   if (INTEL_DEBUG & DEBUG_PIXEL)
-      _mesa_printf("%s: fallback to swrast\n", __FUNCTION__);
-
-   _swrast_Bitmap(ctx, x, y, width, height, unpack, pixels);
+   _mesa_meta_Bitmap(ctx, x, y, width, height, unpack, pixels);
 }