Merge branch 'mesa_7_6_branch'
[mesa.git] / src / mesa / drivers / dri / intel / intel_blit.c
index e1046f4a5ded9a53a61a77677d3c2523ad696a89..43141c509c7c1c2522f5bde12c85418bfe568661 100644 (file)
  **************************************************************************/
 
 
-#include <stdio.h>
-#include <errno.h>
-
 #include "main/mtypes.h"
 #include "main/context.h"
 #include "main/enums.h"
+#include "main/texformat.h"
+#include "main/colormac.h"
 
 #include "intel_blit.h"
 #include "intel_buffers.h"
@@ -40,6 +39,7 @@
 #include "intel_reg.h"
 #include "intel_regions.h"
 #include "intel_batchbuffer.h"
+#include "intel_chipset.h"
 
 #define FILE_DEBUG_FLAG DEBUG_BLIT
 
@@ -97,14 +97,16 @@ intelCopyBuffer(const __DRIdrawablePrivate * dPriv,
       ASSERT(src->cpp == dst->cpp);
 
       if (cpp == 2) {
-        BR13 = (0xCC << 16) | (1 << 24);
+        BR13 = (0xCC << 16) | BR13_565;
         CMD = XY_SRC_COPY_BLT_CMD;
       }
       else {
-        BR13 = (0xCC << 16) | (1 << 24) | (1 << 25);
+        BR13 = (0xCC << 16) | BR13_8888;
         CMD = XY_SRC_COPY_BLT_CMD | XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB;
       }
 
+      assert(src->tiling != I915_TILING_Y);
+      assert(dst->tiling != I915_TILING_Y);
 #ifndef I915
       if (src->tiling != I915_TILING_NONE) {
         CMD |= XY_SRC_TILED;
@@ -172,64 +174,6 @@ intelCopyBuffer(const __DRIdrawablePrivate * dPriv,
    UNLOCK_HARDWARE(intel);
 }
 
-
-
-
-void
-intelEmitFillBlit(struct intel_context *intel,
-                 GLuint cpp,
-                 GLshort dst_pitch,
-                 dri_bo *dst_buffer,
-                 GLuint dst_offset,
-                 uint32_t dst_tiling,
-                 GLshort x, GLshort y,
-                 GLshort w, GLshort h,
-                 GLuint color)
-{
-   GLuint BR13, CMD;
-   BATCH_LOCALS;
-
-   dst_pitch *= cpp;
-
-   switch (cpp) {
-   case 1:
-   case 2:
-   case 3:
-      BR13 = (0xF0 << 16) | (1 << 24);
-      CMD = XY_COLOR_BLT_CMD;
-      break;
-   case 4:
-      BR13 = (0xF0 << 16) | (1 << 24) | (1 << 25);
-      CMD = XY_COLOR_BLT_CMD | XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB;
-      break;
-   default:
-      return;
-   }
-#ifndef I915
-   if (dst_tiling != I915_TILING_NONE) {
-      CMD |= XY_DST_TILED;
-      dst_pitch /= 4;
-   }
-#endif
-
-   DBG("%s dst:buf(%p)/%d+%d %d,%d sz:%dx%d\n",
-       __FUNCTION__, dst_buffer, dst_pitch, dst_offset, x, y, w, h);
-
-   assert(w > 0);
-   assert(h > 0);
-
-   BEGIN_BATCH(6, NO_LOOP_CLIPRECTS);
-   OUT_BATCH(CMD);
-   OUT_BATCH(BR13 | dst_pitch);
-   OUT_BATCH((y << 16) | x);
-   OUT_BATCH(((y + h) << 16) | (x + w));
-   OUT_RELOC(dst_buffer,
-            I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER,
-            dst_offset);
-   OUT_BATCH(color);
-   ADVANCE_BATCH();
-}
-
 static GLuint translate_raster_op(GLenum logicop)
 {
    switch(logicop) {
@@ -256,7 +200,7 @@ static GLuint translate_raster_op(GLenum logicop)
 
 /* Copy BitBlt
  */
-void
+GLboolean
 intelEmitCopyBlit(struct intel_context *intel,
                  GLuint cpp,
                  GLshort src_pitch,
@@ -278,6 +222,19 @@ intelEmitCopyBlit(struct intel_context *intel,
    dri_bo *aper_array[3];
    BATCH_LOCALS;
 
+   if (dst_tiling != I915_TILING_NONE) {
+      if (dst_offset & 4095)
+        return GL_FALSE;
+      if (dst_tiling == I915_TILING_Y)
+        return GL_FALSE;
+   }
+   if (src_tiling != I915_TILING_NONE) {
+      if (src_offset & 4095)
+        return GL_FALSE;
+      if (src_tiling == I915_TILING_Y)
+        return GL_FALSE;
+   }
+
    /* do space/cliprects check before going any further */
    do {
        aper_array[0] = intel->batch->buf;
@@ -292,12 +249,7 @@ intelEmitCopyBlit(struct intel_context *intel,
    } while (pass < 2);
 
    if (pass >= 2) {
-       GLboolean locked = GL_FALSE;       
-       if (!intel->locked) {
-           LOCK_HARDWARE(intel);
-           locked = GL_TRUE;
-       }
-
+       LOCK_HARDWARE(intel);
        dri_bo_map(dst_buffer, GL_TRUE);
        dri_bo_map(src_buffer, GL_FALSE);
        _mesa_copy_rect((GLubyte *)dst_buffer->virtual + dst_offset,
@@ -311,11 +263,9 @@ intelEmitCopyBlit(struct intel_context *intel,
        
        dri_bo_unmap(src_buffer);
        dri_bo_unmap(dst_buffer);
-       
-       if (locked)
-           UNLOCK_HARDWARE(intel);
+       UNLOCK_HARDWARE(intel);
 
-       return;
+       return GL_TRUE;
    }
 
    intel_batchbuffer_require_space(intel->batch, 8 * 4, NO_LOOP_CLIPRECTS);
@@ -331,17 +281,18 @@ intelEmitCopyBlit(struct intel_context *intel,
 
    switch (cpp) {
    case 1:
+      CMD = XY_SRC_COPY_BLT_CMD;
+      break;
    case 2:
-   case 3:
-      BR13 |= (1 << 24);
+      BR13 |= BR13_565;
       CMD = XY_SRC_COPY_BLT_CMD;
       break;
    case 4:
-      BR13 |= (1 << 24) | (1 << 25);
+      BR13 |= BR13_8888;
       CMD = XY_SRC_COPY_BLT_CMD | XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB;
       break;
    default:
-      return;
+      return GL_FALSE;
    }
 
 #ifndef I915
@@ -356,55 +307,30 @@ intelEmitCopyBlit(struct intel_context *intel,
 #endif
 
    if (dst_y2 <= dst_y || dst_x2 <= dst_x) {
-      return;
+      return GL_TRUE;
    }
 
-   /* Initial y values don't seem to work with negative pitches.  If
-    * we adjust the offsets manually (below), it seems to work fine.
-    *
-    * On the other hand, if we always adjust, the hardware doesn't
-    * know which blit directions to use, so overlapping copypixels get
-    * the wrong result.
-    */
-   if (dst_pitch > 0 && src_pitch > 0) {
-      assert(dst_x < dst_x2);
-      assert(dst_y < dst_y2);
-
-      BEGIN_BATCH(8, NO_LOOP_CLIPRECTS);
-      OUT_BATCH(CMD);
-      OUT_BATCH(BR13 | dst_pitch);
-      OUT_BATCH((dst_y << 16) | dst_x);
-      OUT_BATCH((dst_y2 << 16) | dst_x2);
-      OUT_RELOC(dst_buffer,
-               I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER,
-               dst_offset);
-      OUT_BATCH((src_y << 16) | src_x);
-      OUT_BATCH(src_pitch);
-      OUT_RELOC(src_buffer,
-               I915_GEM_DOMAIN_RENDER, 0,
-               src_offset);
-      ADVANCE_BATCH();
-   }
-   else {
-      assert(dst_x < dst_x2);
-      assert(h > 0);
-
-      BEGIN_BATCH(8, NO_LOOP_CLIPRECTS);
-      OUT_BATCH(CMD);
-      OUT_BATCH(BR13 | ((uint16_t)dst_pitch));
-      OUT_BATCH((0 << 16) | dst_x);
-      OUT_BATCH((h << 16) | dst_x2);
-      OUT_RELOC(dst_buffer,
-               I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER,
-               dst_offset + dst_y * dst_pitch);
-      OUT_BATCH((0 << 16) | src_x);
-      OUT_BATCH(src_pitch);
-      OUT_RELOC(src_buffer,
-               I915_GEM_DOMAIN_RENDER, 0,
-               src_offset + src_y * src_pitch);
-      ADVANCE_BATCH();
-   }
+   assert(dst_x < dst_x2);
+   assert(dst_y < dst_y2);
+
+   BEGIN_BATCH(8, NO_LOOP_CLIPRECTS);
+   OUT_BATCH(CMD);
+   OUT_BATCH(BR13 | (uint16_t)dst_pitch);
+   OUT_BATCH((dst_y << 16) | dst_x);
+   OUT_BATCH((dst_y2 << 16) | dst_x2);
+   OUT_RELOC(dst_buffer,
+            I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER,
+            dst_offset);
+   OUT_BATCH((src_y << 16) | src_x);
+   OUT_BATCH((uint16_t)src_pitch);
+   OUT_RELOC(src_buffer,
+            I915_GEM_DOMAIN_RENDER, 0,
+            src_offset);
+   ADVANCE_BATCH();
+
    intel_batchbuffer_emit_mi_flush(intel->batch);
+
+   return GL_TRUE;
 }
 
 
@@ -507,10 +433,9 @@ intelClearWithBlit(GLcontext *ctx, GLbitfield mask)
             const GLbitfield bufBit = 1 << buf;
             if ((clearMask & bufBit) && !(bufBit & skipBuffers)) {
                /* OK, clear this renderbuffer */
-               struct intel_region *irb_region =
-                 intel_get_rb_region(fb, buf);
+              struct intel_renderbuffer *irb = intel_get_renderbuffer(fb, buf);
                dri_bo *write_buffer =
-                  intel_region_buffer(intel, irb_region,
+                  intel_region_buffer(intel, irb->region,
                                       all ? INTEL_WRITE_FULL :
                                       INTEL_WRITE_PART);
 
@@ -518,15 +443,13 @@ intelClearWithBlit(GLcontext *ctx, GLbitfield mask)
                GLint pitch, cpp;
                GLuint BR13, CMD;
 
-               ASSERT(irb_region);
-
-               pitch = irb_region->pitch;
-               cpp = irb_region->cpp;
+               pitch = irb->region->pitch;
+               cpp = irb->region->cpp;
 
                DBG("%s dst:buf(%p)/%d+%d %d,%d sz:%dx%d\n",
                    __FUNCTION__,
-                   irb_region->buffer, (pitch * cpp),
-                   irb_region->draw_offset,
+                   irb->region->buffer, (pitch * cpp),
+                   irb->region->draw_offset,
                    b.x1, b.y1, b.x2 - b.x1, b.y2 - b.y1);
 
               BR13 = 0xf0 << 16;
@@ -534,7 +457,7 @@ intelClearWithBlit(GLcontext *ctx, GLbitfield mask)
 
                /* Setup the blit command */
                if (cpp == 4) {
-                  BR13 |= (1 << 24) | (1 << 25);
+                  BR13 |= BR13_8888;
                   if (buf == BUFFER_DEPTH || buf == BUFFER_STENCIL) {
                      if (clearMask & BUFFER_BIT_DEPTH)
                         CMD |= XY_BLT_WRITE_RGB;
@@ -547,12 +470,14 @@ intelClearWithBlit(GLcontext *ctx, GLbitfield mask)
                   }
                }
                else {
-                  ASSERT(cpp == 2 || cpp == 0);
-                  BR13 |= (1 << 24);
+                  ASSERT(cpp == 2);
+                  BR13 |= BR13_565;
                }
 
+              assert(irb->region->tiling != I915_TILING_Y);
+
 #ifndef I915
-              if (irb_region->tiling != I915_TILING_NONE) {
+              if (irb->region->tiling != I915_TILING_NONE) {
                  CMD |= XY_DST_TILED;
                  pitch /= 4;
               }
@@ -563,14 +488,40 @@ intelClearWithBlit(GLcontext *ctx, GLbitfield mask)
                   clearVal = clear_depth;
                }
                else {
-                  clearVal = (cpp == 4)
-                     ? intel->ClearColor8888 : intel->ClearColor565;
-               }
+                 uint8_t clear[4];
+                 GLclampf *color = ctx->Color.ClearColor;
+
+                 CLAMPED_FLOAT_TO_UBYTE(clear[0], color[0]);
+                 CLAMPED_FLOAT_TO_UBYTE(clear[1], color[1]);
+                 CLAMPED_FLOAT_TO_UBYTE(clear[2], color[2]);
+                 CLAMPED_FLOAT_TO_UBYTE(clear[3], color[3]);
+
+                 switch (irb->texformat->MesaFormat) {
+                 case MESA_FORMAT_ARGB8888:
+                    clearVal = intel->ClearColor8888;
+                    break;
+                 case MESA_FORMAT_RGB565:
+                    clearVal = intel->ClearColor565;
+                    break;
+                 case MESA_FORMAT_ARGB4444:
+                    clearVal = PACK_COLOR_4444(clear[3], clear[0],
+                                               clear[1], clear[2]);
+                    break;
+                 case MESA_FORMAT_ARGB1555:
+                    clearVal = PACK_COLOR_1555(clear[3], clear[0],
+                                               clear[1], clear[2]);
+                    break;
+                 default:
+                    _mesa_problem(ctx, "Unexpected renderbuffer format: %d\n",
+                                  irb->texformat->MesaFormat);
+                    clearVal = 0;
+                 }
+              }
+
                /*
                   _mesa_debug(ctx, "hardware blit clear buf %d rb id %d\n",
                   buf, irb->Base.Name);
                 */
-              intel_wait_flips(intel);
 
                assert(b.x1 < b.x2);
                assert(b.y1 < b.y2);
@@ -582,20 +533,19 @@ intelClearWithBlit(GLcontext *ctx, GLbitfield mask)
                OUT_BATCH((b.y2 << 16) | b.x2);
                OUT_RELOC(write_buffer,
                         I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER,
-                         irb_region->draw_offset);
+                         irb->region->draw_offset);
                OUT_BATCH(clearVal);
                ADVANCE_BATCH();
                clearMask &= ~bufBit;    /* turn off bit, for faster loop exit */
             }
          }
       }
-      intel_batchbuffer_emit_mi_flush(intel->batch);
    }
 
    UNLOCK_HARDWARE(intel);
 }
 
-void
+GLboolean
 intelEmitImmediateColorExpandBlit(struct intel_context *intel,
                                  GLuint cpp,
                                  GLubyte *src_bits, GLuint src_size,
@@ -611,11 +561,19 @@ intelEmitImmediateColorExpandBlit(struct intel_context *intel,
    int dwords = ALIGN(src_size, 8) / 4;
    uint32_t opcode, br13, blit_cmd;
 
+   if (dst_tiling != I915_TILING_NONE) {
+      if (dst_offset & 4095)
+        return GL_FALSE;
+      if (dst_tiling == I915_TILING_Y)
+        return GL_FALSE;
+   }
+
    assert( logic_op - GL_CLEAR >= 0 );
    assert( logic_op - GL_CLEAR < 0x10 );
+   assert(dst_pitch > 0);
 
    if (w < 0 || h < 0)
-      return;
+      return GL_TRUE;
 
    dst_pitch *= cpp;
 
@@ -626,7 +584,7 @@ intelEmitImmediateColorExpandBlit(struct intel_context *intel,
    intel_batchbuffer_require_space( intel->batch,
                                    (8 * 4) +
                                    (3 * 4) +
-                                   dwords,
+                                   dwords * 4,
                                    REFERENCES_CLIPRECTS );
 
    opcode = XY_SETUP_BLT_CMD;
@@ -672,4 +630,46 @@ intelEmitImmediateColorExpandBlit(struct intel_context *intel,
                           REFERENCES_CLIPRECTS );
 
    intel_batchbuffer_emit_mi_flush(intel->batch);
+
+   return GL_TRUE;
+}
+
+/* We don't have a memmove-type blit like some other hardware, so we'll do a
+ * rectangular blit covering a large space, then emit 1-scanline blit at the
+ * end to cover the last if we need.
+ */
+void
+intel_emit_linear_blit(struct intel_context *intel,
+                      drm_intel_bo *dst_bo,
+                      unsigned int dst_offset,
+                      drm_intel_bo *src_bo,
+                      unsigned int src_offset,
+                      unsigned int size)
+{
+   GLuint pitch, height;
+
+   /* The pitch is a signed value. */
+   pitch = MIN2(size, (1 << 15) - 1);
+   height = size / pitch;
+   intelEmitCopyBlit(intel, 1,
+                    pitch, src_bo, src_offset, I915_TILING_NONE,
+                    pitch, dst_bo, dst_offset, I915_TILING_NONE,
+                    0, 0, /* src x/y */
+                    0, 0, /* dst x/y */
+                    pitch, height, /* w, h */
+                    GL_COPY);
+
+   src_offset += pitch * height;
+   dst_offset += pitch * height;
+   size -= pitch * height;
+   assert (size < (1 << 15));
+   if (size != 0) {
+      intelEmitCopyBlit(intel, 1,
+                       size, src_bo, src_offset, I915_TILING_NONE,
+                       size, dst_bo, dst_offset, I915_TILING_NONE,
+                       0, 0, /* src x/y */
+                       0, 0, /* dst x/y */
+                       size, 1, /* w, h */
+                       GL_COPY);
+   }
 }