/**
 * Copy the back color buffer to the front color buffer. 
 * Used for SwapBuffers().
 */
void
intelCopyBuffer(const __DRIdrawablePrivate * dPriv,
                const drm_clip_rect_t * rect)
{

   struct intel_context *intel;
   const intelScreenPrivate *intelScreen;

   DBG("%s\n", __FUNCTION__);

   assert(dPriv);

   intel = intelScreenContext(dPriv->driScreenPriv->private);
   if (!intel)
      return;

   intelScreen = intel->intelScreen;

   if (intel->last_swap_fence) {
      dri_fence_wait(intel->last_swap_fence);
      dri_fence_unreference(intel->last_swap_fence);
      intel->last_swap_fence = NULL;
   }
   intel->last_swap_fence = intel->first_swap_fence;
   intel->first_swap_fence = NULL;

   /* The LOCK_HARDWARE is required for the cliprects.  Buffer offsets
    * should work regardless.
    */
   LOCK_HARDWARE(intel);

   if (dPriv && dPriv->numClipRects) {
      struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
      const struct intel_region *frontRegion
	 = intel_get_rb_region(&intel_fb->Base, BUFFER_FRONT_LEFT);
      const struct intel_region *backRegion
	 = intel_get_rb_region(&intel_fb->Base, BUFFER_BACK_LEFT);
      const int nbox = dPriv->numClipRects;
      const drm_clip_rect_t *pbox = dPriv->pClipRects;
      const int cpp = frontRegion->cpp;
      int src_pitch = backRegion->pitch * cpp;
      int dst_pitch = frontRegion->pitch * cpp;
      int BR13, CMD;
      int i;

      ASSERT(intel_fb);
      ASSERT(intel_fb->Base.Name == 0);    /* Not a user-created FBO */
      ASSERT(frontRegion);
      ASSERT(backRegion);
      ASSERT(frontRegion->pitch == backRegion->pitch);
      ASSERT(frontRegion->cpp == backRegion->cpp);

      if (cpp == 2) {
	 BR13 = (0xCC << 16) | (1 << 24);
	 CMD = XY_SRC_COPY_BLT_CMD;
      }
      else {
	 BR13 = (0xCC << 16) | (1 << 24) | (1 << 25);
	 CMD = XY_SRC_COPY_BLT_CMD | XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB;
      }

#ifndef I915
      if (backRegion->tiled) {
	 CMD |= XY_SRC_TILED;
	 src_pitch /= 4;
      }
      if (frontRegion->tiled) {
	 CMD |= XY_DST_TILED;
	 dst_pitch /= 4;
      }
#endif

      for (i = 0; i < nbox; i++, pbox++) {
	 drm_clip_rect_t box;

	 if (pbox->x1 >= pbox->x2 ||
	     pbox->y1 >= pbox->y2 ||
	     pbox->x2 > intelScreen->width || pbox->y2 > intelScreen->height)
	    continue;

	 box = *pbox;

	 if (rect) {
	    if (rect->x1 > box.x1)
	       box.x1 = rect->x1;
	    if (rect->y1 > box.y1)
	       box.y1 = rect->y1;
	    if (rect->x2 < box.x2)
	       box.x2 = rect->x2;
	    if (rect->y2 < box.y2)
	       box.y2 = rect->y2;

	    if (box.x1 >= box.x2 || box.y1 >= box.y2)
	       continue;
	 }

	 assert(box.x1 < box.x2);
	 assert(box.y1 < box.y2);

	 BEGIN_BATCH(8, INTEL_BATCH_NO_CLIPRECTS);
	 OUT_BATCH(CMD);
	 OUT_BATCH(BR13 | dst_pitch);
	 OUT_BATCH((box.y1 << 16) | box.x1);
	 OUT_BATCH((box.y2 << 16) | box.x2);

	 OUT_RELOC(frontRegion->buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE,
		   0);
	 OUT_BATCH((box.y1 << 16) | box.x1);
	 OUT_BATCH(src_pitch);
	 OUT_RELOC(backRegion->buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_READ,
		   0);

	 ADVANCE_BATCH();
      }

      if (intel->first_swap_fence)
	 dri_fence_unreference(intel->first_swap_fence);
      intel_batchbuffer_flush(intel->batch);
      intel->first_swap_fence = intel->batch->last_fence;
      if (intel->first_swap_fence)
	 dri_fence_reference(intel->first_swap_fence);
   }

   UNLOCK_HARDWARE(intel);
}
void
intel_exec_ioctl(struct intel_context *intel,
		 GLuint used,
		 GLboolean ignore_cliprects, GLboolean allow_unlock,
		 void *start, GLuint count, dri_fence **fence)
{
   struct drm_i915_execbuffer execbuf;
   dri_fence *fo;
   int ret;

   assert(intel->locked);
   assert(used);

   if (intel->no_hw)
      return;

   if (*fence) {
     dri_fence_unreference(*fence);
   }

   memset(&execbuf, 0, sizeof(execbuf));

   execbuf.num_buffers = count;
   execbuf.batch.used = used;
   execbuf.batch.cliprects = intel->pClipRects;
   execbuf.batch.num_cliprects = ignore_cliprects ? 0 : intel->numClipRects;
   execbuf.batch.DR1 = 0;
   execbuf.batch.DR4 = ((((GLuint) intel->drawX) & 0xffff) |
			(((GLuint) intel->drawY) << 16));

   execbuf.ops_list = (unsigned long)start; // TODO
   execbuf.fence_arg.flags = DRM_FENCE_FLAG_SHAREABLE | DRM_I915_FENCE_FLAG_FLUSHED;

   do {
      ret = drmCommandWriteRead(intel->driFd, DRM_I915_EXECBUFFER, &execbuf,
				sizeof(execbuf));
   } while (ret == -EAGAIN);

   if (ret != 0) {
      fprintf(stderr, "DRM_I915_EXECBUFFER: %d\n", -errno);
      UNLOCK_HARDWARE(intel);
      exit(1);
   }

   if (execbuf.fence_arg.error != 0) {

      /*
       * Fence creation has failed, but the GPU has been
       * idled by the kernel. Safe to continue.
       */ 

      *fence = NULL;
      return;
   }

   fo = intel_ttm_fence_create_from_arg(intel->bufmgr, "fence buffers",
					&execbuf.fence_arg);
   if (!fo) {
      fprintf(stderr, "failed to fence handle: %08x\n", execbuf.fence_arg.handle);
      UNLOCK_HARDWARE(intel);
      exit(1);
   }
   *fence = fo;
}
/**
 * Copy the back color buffer to the front color buffer. 
 * Used for SwapBuffers().
 */
void
intelCopyBuffer(const __DRIdrawablePrivate * dPriv,
                const drm_clip_rect_t * rect)
{

   struct intel_context *intel;
   const intelScreenPrivate *intelScreen;
   int ret;

   DBG("%s\n", __FUNCTION__);

   assert(dPriv);

   intel = intelScreenContext(dPriv->driScreenPriv->private);
   if (!intel)
      return;

   intelScreen = intel->intelScreen;

   if (intel->last_swap_fence) {
      dri_fence_wait(intel->last_swap_fence);
      dri_fence_unreference(intel->last_swap_fence);
      intel->last_swap_fence = NULL;
   }
   intel->last_swap_fence = intel->first_swap_fence;
   intel->first_swap_fence = NULL;

   /* The LOCK_HARDWARE is required for the cliprects.  Buffer offsets
    * should work regardless.
    */
   LOCK_HARDWARE(intel);

   if (dPriv && dPriv->numClipRects) {
      struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
      struct intel_region *src, *dst;
      int nbox = dPriv->numClipRects;
      drm_clip_rect_t *pbox = dPriv->pClipRects;
      int cpp;
      int src_pitch, dst_pitch;
      unsigned short src_x, src_y;
      int BR13, CMD;
      int i;

      src = intel_get_rb_region(&intel_fb->Base, BUFFER_BACK_LEFT);
      dst = intel_get_rb_region(&intel_fb->Base, BUFFER_FRONT_LEFT);

      src_pitch = src->pitch * src->cpp;
      dst_pitch = dst->pitch * dst->cpp;

      cpp = src->cpp;

      ASSERT(intel_fb);
      ASSERT(intel_fb->Base.Name == 0);    /* Not a user-created FBO */
      ASSERT(src);
      ASSERT(dst);
      ASSERT(src->cpp == dst->cpp);

      if (cpp == 2) {
	 BR13 = (0xCC << 16) | (1 << 24);
	 CMD = XY_SRC_COPY_BLT_CMD;
      }
      else {
	 BR13 = (0xCC << 16) | (1 << 24) | (1 << 25);
	 CMD = XY_SRC_COPY_BLT_CMD | XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB;
      }

#ifndef I915
      if (src->tiled) {
	 CMD |= XY_SRC_TILED;
	 src_pitch /= 4;
      }
      if (dst->tiled) {
	 CMD |= XY_DST_TILED;
	 dst_pitch /= 4;
      }
#endif
      /* do space/cliprects check before going any further */
      intel_batchbuffer_require_space(intel->batch, 8 * 4, REFERENCES_CLIPRECTS);
   again:
      ret = dri_bufmgr_check_aperture_space(dst->buffer);
      ret |= dri_bufmgr_check_aperture_space(src->buffer);
      
      if (ret) {
	intel_batchbuffer_flush(intel->batch);
	goto again;
      }
      
      for (i = 0; i < nbox; i++, pbox++) {
	 drm_clip_rect_t box = *pbox;

	 if (rect) {
	    if (!intel_intersect_cliprects(&box, &box, rect))
	       continue;
	 }

	 if (box.x1 >= box.x2 ||
	     box.y1 >= box.y2)
	    continue;

	 assert(box.x1 < box.x2);
	 assert(box.y1 < box.y2);
	 src_x = box.x1 - dPriv->x + dPriv->backX;
	 src_y = box.y1 - dPriv->y + dPriv->backY;

	 BEGIN_BATCH(8, REFERENCES_CLIPRECTS);
	 OUT_BATCH(CMD);
	 OUT_BATCH(BR13 | dst_pitch);
	 OUT_BATCH((box.y1 << 16) | box.x1);
	 OUT_BATCH((box.y2 << 16) | box.x2);

	 OUT_RELOC(dst->buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE, 0);
	 OUT_BATCH((src_y << 16) | src_x);
	 OUT_BATCH(src_pitch);
	 OUT_RELOC(src->buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_READ, 0);
	 ADVANCE_BATCH();
      }

      if (intel->first_swap_fence)
	 dri_fence_unreference(intel->first_swap_fence);
      intel_batchbuffer_flush(intel->batch);
      intel->first_swap_fence = intel->batch->last_fence;
      if (intel->first_swap_fence)
	 dri_fence_reference(intel->first_swap_fence);
   }

   UNLOCK_HARDWARE(intel);
}