/*
 * Copyright © 2009 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS 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.
 *
 * Authors:
 *    Zhigang Gong <zhigang.gong@linux.intel.com>
 *
 */

#ifndef GLAMOR_PRIV_H
#error This file can only be included by glamor_priv.h
#endif

#ifndef __GLAMOR_UTILS_H__
#define __GLAMOR_UTILS_H__

#define v_from_x_coord_x(_xscale_, _x_)          ( 2 * (_x_) * (_xscale_) - 1.0)
#define v_from_x_coord_y(_yscale_, _y_)          (-2 * (_y_) * (_yscale_) + 1.0)
#define v_from_x_coord_y_inverted(_yscale_, _y_) (2 * (_y_) * (_yscale_) - 1.0)
#define t_from_x_coord_x(_xscale_, _x_)          ((_x_) * (_xscale_))
#define t_from_x_coord_y(_yscale_, _y_)          (1.0 - (_y_) * (_yscale_))
#define t_from_x_coord_y_inverted(_yscale_, _y_) ((_y_) * (_yscale_))

#define pixmap_priv_get_dest_scale(_pixmap_priv_, _pxscale_, _pyscale_)  \
  do {                                                                   \
    int _w_,_h_;                                                         \
    PIXMAP_PRIV_GET_ACTUAL_SIZE(_pixmap_priv_, _w_, _h_);                \
    *(_pxscale_) = 1.0 / _w_;                                            \
    *(_pyscale_) = 1.0 / _h_;                                            \
   } while(0)

#define pixmap_priv_get_scale(_pixmap_priv_, _pxscale_, _pyscale_)	\
   do {									\
    *(_pxscale_) = 1.0 / (_pixmap_priv_)->base.fbo->width;			\
    *(_pyscale_) = 1.0 / (_pixmap_priv_)->base.fbo->height;			\
  } while(0)

#define GLAMOR_PIXMAP_FBO_NOT_EAXCT_SIZE(priv)			\
   (priv->base.fbo->width != priv->base.pixmap->drawable.width 	\
      || priv->base.fbo->height != priv->base.pixmap->drawable.height)	\

#define PIXMAP_PRIV_GET_ACTUAL_SIZE(priv, w, h)			\
  do {								\
	if (unlikely(priv->type == GLAMOR_TEXTURE_LARGE)) {		\
		w = priv->large.box.x2 - priv->large.box.x1;	\
		h = priv->large.box.y2 - priv->large.box.y1;	\
	} else {						\
		w = priv->base.pixmap->drawable.width;		\
		h = priv->base.pixmap->drawable.height;		\
	}							\
  } while(0)

#define glamor_pixmap_fbo_fix_wh_ratio(wh, priv)  		\
  do {								\
	int actual_w, actual_h;					\
	PIXMAP_PRIV_GET_ACTUAL_SIZE(priv, actual_w, actual_h);	\
	wh[0] = (float)priv->base.fbo->width / actual_w;	\
	wh[1] = (float)priv->base.fbo->height / actual_h;	\
	wh[2] = 1.0 / priv->base.fbo->width;			\
	wh[3] = 1.0 / priv->base.fbo->height;			\
  } while(0)

#define pixmap_priv_get_fbo_off(_priv_, _xoff_, _yoff_)		\
   do {								\
	if (unlikely(_priv_ && (_priv_)->type == GLAMOR_TEXTURE_LARGE)) {  \
		*(_xoff_) = - (_priv_)->large.box.x1;	\
		*(_yoff_) = - (_priv_)->large.box.y1;	\
	} else {						\
		*(_xoff_) = 0;					\
		*(_yoff_) = 0;					\
	}							\
   } while(0)

#define xFixedToFloat(_val_) ((float)xFixedToInt(_val_)			\
			      + ((float)xFixedFrac(_val_) / 65536.0))

#define glamor_picture_get_matrixf(_picture_, _matrix_)			\
  do {									\
    int _i_;								\
    if ((_picture_)->transform)						\
      {									\
	for(_i_ = 0; _i_ < 3; _i_++)					\
	  {								\
	    (_matrix_)[_i_ * 3 + 0] =					\
	      xFixedToFloat((_picture_)->transform->matrix[_i_][0]);	\
	    (_matrix_)[_i_ * 3 + 1] =					\
	      xFixedToFloat((_picture_)->transform->matrix[_i_][1]);	\
	    (_matrix_)[_i_ * 3 + 2] = \
	      xFixedToFloat((_picture_)->transform->matrix[_i_][2]);	\
	  }								\
      }									\
  }  while(0)

#define fmod(x, w)		(x - w * floor((float)x/w))

#define fmodulus(x, w, c)	do {c = fmod(x, w);		\
				    c = c >= 0 ? c : c + w;}	\
				while(0)
/* @x: is current coord
 * @x2: is the right/bottom edge
 * @w: is current width or height
 * @odd: is output value, 0 means we are in an even region, 1 means we are in a
 * odd region.
 * @c: is output value, equal to x mod w. */
#define fodd_repeat_mod(x, x2, w, odd, c)	\
  do {						\
	float shift;				\
	fmodulus((x), w, c); 			\
	shift = fabs((x) - (c));		\
	shift = floor(fabs(round(shift)) / w);	\
	odd = (int)shift & 1;			\
	if (odd && (((x2 % w) == 0) &&		\
	    round(fabs(x)) == x2))		\
		odd = 0;			\
  } while(0)

/* @txy: output value, is the corrected coords.
 * @xy: input coords to be fixed up.
 * @cd: xy mod wh, is a input value.
 * @wh: current width or height.
 * @bxy1,bxy2: current box edge's x1/x2 or y1/y2
 *
 * case 1:
 *  ----------
 *  |  *     |
 *  |        |
 *  ----------
 *  tx = (c - x1) mod w
 *
 *  case 2:
 *     ---------
 *  *  |       |
 *     |       |
 *     ---------
 *   tx = - (c - (x1 mod w))
 *
 *   case 3:
 *
 *   ----------
 *   |        |  *
 *   |        |
 *   ----------
 *   tx = ((x2 mod x) - c) + (x2 - x1)
 **/
#define __glamor_repeat_reflect_fixup(txy, xy,		\
				cd, wh, bxy1, bxy2)	\
  do {							\
	cd = wh - cd;					\
	if ( xy >= bxy1 && xy < bxy2) {			\
		cd = cd - bxy1;				\
		fmodulus(cd, wh, txy);			\
	} else	if (xy < bxy1) {			\
		float bxy1_mod;				\
		fmodulus(bxy1, wh, bxy1_mod);		\
		txy = -(cd - bxy1_mod);			\
	}						\
	else if (xy >= bxy2)	{			\
		float bxy2_mod;				\
		fmodulus(bxy2, wh, bxy2_mod);		\
		if (bxy2_mod == 0)			\
			bxy2_mod = wh;			\
		txy = (bxy2_mod - cd) + bxy2 - bxy1;	\
	} else {assert(0); txy = 0;}			\
  } while(0)

#define _glamor_repeat_reflect_fixup(txy, xy, cd, odd,	\
				     wh, bxy1, bxy2)	\
  do {							\
	if (odd) {					\
		__glamor_repeat_reflect_fixup(txy, xy, 	\
			cd, wh, bxy1, bxy2);		\
	} else						\
		txy = xy - bxy1;			\
  } while(0)

#define _glamor_get_reflect_transform_coords(priv, repeat_type,	\
					    tx1, ty1, 		\
				            _x1_, _y1_)		\
  do {								\
	int odd_x, odd_y;					\
	float c, d;						\
	fodd_repeat_mod(_x1_,priv->box.x2,			\
		    priv->base.pixmap->drawable.width,		\
		    odd_x, c);					\
	fodd_repeat_mod(_y1_,	priv->box.y2,			\
		    priv->base.pixmap->drawable.height,		\
		    odd_y, d);					\
	DEBUGF("c %f d %f oddx %d oddy %d \n",			\
		c, d, odd_x, odd_y);				\
	DEBUGF("x2 %d x1 %d fbo->width %d \n", priv->box.x2,	\
		priv->box.x1, priv->base.fbo->width);		\
	DEBUGF("y2 %d y1 %d fbo->height %d \n", priv->box.y2, 	\
		priv->box.y1, priv->base.fbo->height);		\
	_glamor_repeat_reflect_fixup(tx1, _x1_, c, odd_x,	\
		priv->base.pixmap->drawable.width,		\
		priv->box.x1, priv->box.x2);			\
	_glamor_repeat_reflect_fixup(ty1, _y1_, d, odd_y,	\
		priv->base.pixmap->drawable.height,		\
		priv->box.y1, priv->box.y2);			\
   } while(0)

#define _glamor_get_repeat_coords(priv, repeat_type, tx1,	\
				  ty1, tx2, ty2,		\
				  _x1_, _y1_, _x2_,		\
				  _y2_, c, d, odd_x, odd_y)	\
  do {								\
	if (repeat_type == RepeatReflect) {			\
		DEBUGF("x1 y1 %d %d\n",				\
			_x1_, _y1_ );				\
		DEBUGF("width %d box.x1 %d \n",			\
		       (priv)->base.pixmap->drawable.width,	\
		       priv->box.x1);				\
		if (odd_x) {					\
			c = (priv)->base.pixmap->drawable.width	\
				- c;				\
			tx1 = c - priv->box.x1;			\
			tx2 = tx1 - ((_x2_) - (_x1_));		\
		} else {					\
			tx1 = c - priv->box.x1;			\
			tx2 = tx1 + ((_x2_) - (_x1_));		\
		}						\
		if (odd_y){					\
			d = (priv)->base.pixmap->drawable.height\
			    - d;				\
			ty1 = d - priv->box.y1;			\
			ty2 = ty1 - ((_y2_) - (_y1_));		\
		} else {					\
			ty1 = d - priv->box.y1;			\
			ty2 = ty1 + ((_y2_) - (_y1_));		\
		}						\
	} else { /* RepeatNormal*/				\
		tx1 = (c - priv->box.x1);  			\
		ty1 = (d - priv->box.y1);			\
		tx2 = tx1 + ((_x2_) - (_x1_));			\
		ty2 = ty1 + ((_y2_) - (_y1_));			\
	}							\
   } while(0)


/* _x1_ ... _y2_ may has fractional. */
#define glamor_get_repeat_transform_coords(priv, repeat_type, tx1,	\
					   ty1, _x1_, _y1_)		\
  do {									\
	DEBUGF("width %d box.x1 %d x2 %d y1 %d y2 %d\n",		\
		(priv)->base.pixmap->drawable.width,			\
		priv->box.x1, priv->box.x2, priv->box.y1,		\
		priv->box.y2);						\
	DEBUGF("x1 %f y1 %f \n", _x1_, _y1_);				\
	if (repeat_type != RepeatReflect) {				\
		tx1 = _x1_ - priv->box.x1;				\
		ty1 = _y1_ - priv->box.y1;				\
	} else			\
		_glamor_get_reflect_transform_coords(priv, repeat_type, \
				  tx1, ty1, 				\
				  _x1_, _y1_);				\
	DEBUGF("tx1 %f ty1 %f \n", tx1, ty1);				\
   } while(0)

/* _x1_ ... _y2_ must be integer. */
#define glamor_get_repeat_coords(priv, repeat_type, tx1,		\
				 ty1, tx2, ty2, _x1_, _y1_, _x2_,	\
				 _y2_) 					\
  do {									\
	int c, d;							\
	int odd_x = 0, odd_y = 0;					\
	DEBUGF("width %d box.x1 %d x2 %d y1 %d y2 %d\n",		\
		(priv)->base.pixmap->drawable.width,			\
		priv->box.x1, priv->box.x2,				\
		priv->box.y1, priv->box.y2);				\
	modulus((_x1_), (priv)->base.pixmap->drawable.width, c); 	\
	modulus((_y1_), (priv)->base.pixmap->drawable.height, d);	\
	DEBUGF("c %d d %d \n", c, d);					\
	if (repeat_type == RepeatReflect) {				\
		odd_x = abs((_x1_ - c)					\
			/ (priv->base.pixmap->drawable.width)) & 1;	\
		odd_y = abs((_y1_ - d)					\
			/ (priv->base.pixmap->drawable.height)) & 1;	\
	}								\
	_glamor_get_repeat_coords(priv, repeat_type, tx1, ty1, tx2, ty2,\
				  _x1_, _y1_, _x2_, _y2_, c, d,		\
				  odd_x, odd_y);			\
   } while(0)

#define glamor_transform_point(matrix, tx, ty, x, y)			\
  do {									\
    int _i_;								\
    float _result_[4];							\
    for (_i_ = 0; _i_ < 3; _i_++) {					\
      _result_[_i_] = (matrix)[_i_ * 3] * (x) + (matrix)[_i_ * 3 + 1] * (y)	\
	+ (matrix)[_i_ * 3 + 2];					\
    }									\
    tx = _result_[0] / _result_[2];					\
    ty = _result_[1] / _result_[2];					\
  } while(0)

#define _glamor_set_normalize_tpoint(xscale, yscale, _tx_, _ty_,	\
				     texcoord, yInverted)		\
  do {									\
	(texcoord)[0] = t_from_x_coord_x(xscale, _tx_);			\
	if (likely(yInverted))						\
		(texcoord)[1] = t_from_x_coord_y_inverted(yscale, _ty_);\
	else								\
		(texcoord)[1] = t_from_x_coord_y(yscale, _ty_);		\
        DEBUGF("normalized point tx %f ty %f \n", (texcoord)[0],	\
		(texcoord)[1]);						\
  } while(0)

#define glamor_set_transformed_point(priv, matrix, xscale,		\
				     yscale, texcoord,			\
                                     x, y, 				\
				     yInverted)				\
  do {									\
    float tx, ty;							\
    int fbo_x_off, fbo_y_off;						\
    pixmap_priv_get_fbo_off(priv, &fbo_x_off, &fbo_y_off);		\
    glamor_transform_point(matrix, tx, ty, x, y);			\
    DEBUGF("tx %f ty %f fbooff %d %d \n",				\
	    tx, ty, fbo_x_off, fbo_y_off);				\
									\
    tx += fbo_x_off;							\
    ty += fbo_y_off;							\
    (texcoord)[0] = t_from_x_coord_x(xscale, tx);			\
    if (likely(yInverted))							\
      (texcoord)[1] = t_from_x_coord_y_inverted(yscale, ty);		\
    else								\
      (texcoord)[1] = t_from_x_coord_y(yscale, ty);			\
    DEBUGF("normalized tx %f ty %f \n", (texcoord)[0], (texcoord)[1]);	\
  } while(0)

#define glamor_set_transformed_normalize_tri_tcoords(priv,		\
						     matrix,		\
						     xscale,		\
						     yscale,		\
						     vtx,		\
						     yInverted,		\
						     texcoords)		\
    do {								\
	glamor_set_transformed_point(priv, matrix, xscale, yscale,	\
				     texcoords, (vtx)[0], (vtx)[1],	\
				     yInverted);			\
	glamor_set_transformed_point(priv, matrix, xscale, yscale,	\
				     texcoords+2, (vtx)[2], (vtx)[3],	\
				     yInverted);			\
	glamor_set_transformed_point(priv, matrix, xscale, yscale,	\
				     texcoords+4, (vtx)[4], (vtx)[5],	\
				     yInverted);			\
    } while (0)

#define glamor_set_transformed_normalize_tcoords_ext( priv,		\
						  matrix,		\
						  xscale,		\
						  yscale,		\
                                                  tx1, ty1, tx2, ty2,   \
                                                  yInverted, texcoords,	\
						  stride)		\
  do {									\
    glamor_set_transformed_point(priv, matrix, xscale, yscale,		\
				 texcoords, tx1, ty1,			\
				 yInverted);				\
    glamor_set_transformed_point(priv, matrix, xscale, yscale,		\
				 texcoords + 1 * stride, tx2, ty1,	\
				 yInverted);				\
    glamor_set_transformed_point(priv, matrix, xscale, yscale,		\
				 texcoords + 2 * stride, tx2, ty2,	\
				 yInverted);				\
    glamor_set_transformed_point(priv, matrix, xscale, yscale,		\
				 texcoords + 3 * stride, tx1, ty2,	\
				 yInverted);				\
  } while (0)

#define glamor_set_transformed_normalize_tcoords( priv,			\
						  matrix,		\
						  xscale,		\
						  yscale,		\
                                                  tx1, ty1, tx2, ty2,   \
                                                  yInverted, texcoords)	\
  do {									\
	glamor_set_transformed_normalize_tcoords_ext( priv,		\
						  matrix,		\
						  xscale,		\
						  yscale,		\
                                                  tx1, ty1, tx2, ty2,   \
                                                  yInverted, texcoords,	\
						  2);			\
  } while (0)



#define glamor_set_normalize_tri_tcoords(xscale,		\
					 yscale,		\
					 vtx,			\
					 yInverted,		\
					 texcoords)		\
    do {							\
	_glamor_set_normalize_tpoint(xscale, yscale,		\
				(vtx)[0], (vtx)[1],		\
				texcoords,			\
				yInverted);			\
	_glamor_set_normalize_tpoint(xscale, yscale,		\
				(vtx)[2], (vtx)[3],		\
				texcoords+2,			\
				yInverted);			\
	_glamor_set_normalize_tpoint(xscale, yscale,		\
				(vtx)[4], (vtx)[5],		\
				texcoords+4,			\
				yInverted);			\
    } while (0)

#define glamor_set_repeat_transformed_normalize_tcoords_ext( priv,	\
							 repeat_type,	\
							 matrix,	\
							 xscale,	\
							 yscale,	\
							 _x1_, _y1_,	\
							 _x2_, _y2_,   	\
							 yInverted,	\
							 texcoords,	\
							 stride)	\
  do {									\
    if (likely(priv->type != GLAMOR_TEXTURE_LARGE)) {			\
	glamor_set_transformed_normalize_tcoords_ext(priv, matrix, xscale,	\
						 yscale, _x1_, _y1_,	\
						 _x2_, _y2_, yInverted,	\
						 texcoords, stride);	\
    } else {								\
    float tx1, ty1, tx2, ty2, tx3, ty3, tx4, ty4;			\
    float ttx1, tty1, ttx2, tty2, ttx3, tty3, ttx4, tty4;		\
    DEBUGF("original coords %d %d %d %d\n", _x1_, _y1_, _x2_, _y2_);	\
    glamor_transform_point(matrix, tx1, ty1, _x1_, _y1_);		\
    glamor_transform_point(matrix, tx2, ty2, _x2_, _y1_);		\
    glamor_transform_point(matrix, tx3, ty3, _x2_, _y2_);		\
    glamor_transform_point(matrix, tx4, ty4, _x1_, _y2_);		\
    DEBUGF("transformed %f %f %f %f %f %f %f %f\n",			\
	   tx1, ty1, tx2, ty2, tx3, ty3, tx4, ty4);			\
    glamor_get_repeat_transform_coords((&priv->large), repeat_type, 	\
				       ttx1, tty1, 			\
				       tx1, ty1);			\
    glamor_get_repeat_transform_coords((&priv->large), repeat_type, 	\
				       ttx2, tty2, 			\
				       tx2, ty2);			\
    glamor_get_repeat_transform_coords((&priv->large), repeat_type, 	\
				       ttx3, tty3, 			\
				       tx3, ty3);			\
    glamor_get_repeat_transform_coords((&priv->large), repeat_type, 	\
				       ttx4, tty4, 			\
				       tx4, ty4);			\
    DEBUGF("repeat transformed %f %f %f %f %f %f %f %f\n", ttx1, tty1, 	\
	    ttx2, tty2,	ttx3, tty3, ttx4, tty4);			\
    _glamor_set_normalize_tpoint(xscale, yscale, ttx1, tty1,		\
				 texcoords, yInverted);			\
    _glamor_set_normalize_tpoint(xscale, yscale, ttx2, tty2,		\
				 texcoords + 1 * stride, yInverted);	\
    _glamor_set_normalize_tpoint(xscale, yscale, ttx3, tty3,		\
				 texcoords + 2 * stride, yInverted);	\
    _glamor_set_normalize_tpoint(xscale, yscale, ttx4, tty4,		\
				 texcoords + 3 * stride, yInverted);	\
   }									\
  } while (0)


#define glamor_set_repeat_transformed_normalize_tcoords( priv,		\
							 repeat_type,	\
							 matrix,	\
							 xscale,	\
							 yscale,	\
							 _x1_, _y1_,	\
							 _x2_, _y2_,   	\
							 yInverted,	\
							 texcoords)	\
  do {									\
	glamor_set_repeat_transformed_normalize_tcoords_ext( priv,	\
							 repeat_type,	\
							 matrix,	\
							 xscale,	\
							 yscale,	\
							 _x1_, _y1_,	\
							 _x2_, _y2_,   	\
							 yInverted,	\
							 texcoords,	\
							 2);	\
  } while (0)

#define _glamor_set_normalize_tcoords(xscale, yscale, tx1,		\
				      ty1, tx2, ty2,			\
				      yInverted, vertices, stride)	\
  do {									\
    /* vertices may be write-only, so we use following			\
     * temporary variable. */ 						\
    float _t0_, _t1_, _t2_, _t5_;					\
    (vertices)[0] = _t0_ = t_from_x_coord_x(xscale, tx1);		\
    (vertices)[1 * stride] = _t2_ = t_from_x_coord_x(xscale, tx2);	\
    (vertices)[2 * stride] = _t2_;					\
    (vertices)[3 * stride] = _t0_;					\
    if (likely(yInverted)) {							\
      (vertices)[1] = _t1_ = t_from_x_coord_y_inverted(yscale, ty1);	\
      (vertices)[2 * stride + 1] = _t5_ = t_from_x_coord_y_inverted(yscale, ty2);\
    }									\
    else {								\
      (vertices)[1] = _t1_ = t_from_x_coord_y(yscale, ty1);		\
      (vertices)[2 * stride + 1] = _t5_ = t_from_x_coord_y(yscale, ty2);\
    }									\
    (vertices)[1 * stride + 1] = _t1_;					\
    (vertices)[3 * stride + 1] = _t5_;					\
  } while(0)

#define glamor_set_normalize_tcoords_ext(priv, xscale, yscale,		\
				     x1, y1, x2, y2,			\
                                     yInverted, vertices, stride)	\
  do {									\
     if (unlikely(priv->type == GLAMOR_TEXTURE_LARGE)) {				\
	float tx1, tx2, ty1, ty2;					\
	int fbo_x_off, fbo_y_off;					\
	pixmap_priv_get_fbo_off(priv, &fbo_x_off, &fbo_y_off);		\
	tx1 = x1 + fbo_x_off; 						\
	tx2 = x2 + fbo_x_off;						\
	ty1 = y1 + fbo_y_off;						\
	ty2 = y2 + fbo_y_off;						\
	_glamor_set_normalize_tcoords(xscale, yscale, tx1, ty1,		\
				   tx2, ty2, yInverted, vertices,	\
				   stride);				\
     } else								\
	_glamor_set_normalize_tcoords(xscale, yscale, x1, y1,		\
				   x2, y2, yInverted, vertices, stride);\
 } while(0)


#define glamor_set_normalize_tcoords(priv, xscale, yscale,		\
				     x1, y1, x2, y2,			\
                                     yInverted, vertices)		\
  do {									\
	glamor_set_normalize_tcoords_ext(priv, xscale, yscale,		\
				     x1, y1, x2, y2,			\
                                     yInverted, vertices, 2);		\
 } while(0)

#define glamor_set_repeat_normalize_tcoords_ext(priv, repeat_type,	\
					    xscale, yscale,		\
					    _x1_, _y1_, _x2_, _y2_,	\
	                                    yInverted, vertices, stride)\
  do {									\
     if (unlikely(priv->type == GLAMOR_TEXTURE_LARGE)) {				\
	float tx1, tx2, ty1, ty2;					\
	if (repeat_type == RepeatPad) {					\
		tx1 = _x1_ - priv->large.box.x1;			\
		ty1 = _y1_ - priv->large.box.y1;			\
		tx2 = tx1 + ((_x2_) - (_x1_));				\
		ty2 = ty1 + ((_y2_) - (_y1_));				\
	} else {							\
	glamor_get_repeat_coords((&priv->large), repeat_type,		\
				 tx1, ty1, tx2, ty2,			\
				 _x1_, _y1_, _x2_, _y2_);		\
	}								\
	_glamor_set_normalize_tcoords(xscale, yscale, tx1, ty1,		\
				   tx2, ty2, yInverted, vertices,	\
				   stride);				\
     } else								\
	_glamor_set_normalize_tcoords(xscale, yscale, _x1_, _y1_,	\
				   _x2_, _y2_, yInverted, vertices,	\
				   stride);				\
 } while(0)


#define glamor_set_repeat_normalize_tcoords(priv, repeat_type,		\
					    xscale, yscale,		\
					    _x1_, _y1_, _x2_, _y2_,	\
	                                    yInverted, vertices)	\
  do {									\
	glamor_set_repeat_normalize_tcoords_ext(priv, repeat_type,	\
					    xscale, yscale,		\
					    _x1_, _y1_, _x2_, _y2_,	\
	                                    yInverted, vertices, 2);	\
 } while(0)

#define glamor_set_normalize_tcoords_tri_stripe(xscale, yscale,		\
						x1, y1, x2, y2,		\
						yInverted, vertices)	\
    do {								\
	(vertices)[0] = t_from_x_coord_x(xscale, x1);			\
	(vertices)[2] = t_from_x_coord_x(xscale, x2);			\
	(vertices)[6] = (vertices)[2];					\
	(vertices)[4] = (vertices)[0];					\
	if (likely(yInverted)) {						\
	    (vertices)[1] = t_from_x_coord_y_inverted(yscale, y1);	\
	    (vertices)[7] = t_from_x_coord_y_inverted(yscale, y2);	\
	}								\
	else {								\
	    (vertices)[1] = t_from_x_coord_y(yscale, y1);		\
	    (vertices)[7] = t_from_x_coord_y(yscale, y2);		\
	}								\
	(vertices)[3] = (vertices)[1];					\
	(vertices)[5] = (vertices)[7];					\
    } while(0)

#define glamor_set_tcoords(width, height, x1, y1, x2, y2,	\
			   yInverted, vertices)			\
    do {							\
	(vertices)[0] = (x1);					\
	(vertices)[2] = (x2);					\
	(vertices)[4] = (vertices)[2];				\
	(vertices)[6] = (vertices)[0];				\
	if (likely(yInverted)) {					\
	    (vertices)[1] = (y1);				\
	    (vertices)[5] = (y2);				\
	}							\
	else {							\
	    (vertices)[1] = height - (y2);			\
	    (vertices)[5] = height - (y1);			\
	}							\
	(vertices)[3] = (vertices)[1];				\
	(vertices)[7] = (vertices)[5];				\
    } while(0)

#define glamor_set_tcoords_ext(width, height, x1, y1, x2, y2,	\
			       yInverted, vertices, stride)	\
    do {							\
	(vertices)[0] = (x1);					\
	(vertices)[1*stride] = (x2);				\
	(vertices)[2*stride] = (vertices)[1*stride];		\
	(vertices)[3*stride] = (vertices)[0];			\
	if (likely(yInverted)) {				\
	    (vertices)[1] = (y1);				\
	    (vertices)[2*stride + 1] = (y2);			\
	}							\
	else {							\
	    (vertices)[1] = height - (y2);			\
	    (vertices)[2*stride + 1] = height - (y1);		\
	}							\
	(vertices)[1*stride + 1] = (vertices)[1];		\
	(vertices)[3*stride + 1] = (vertices)[2*stride + 1];	\
    } while(0)

#define glamor_set_normalize_one_vcoord(xscale, yscale, x, y,		\
					yInverted, vertices)		\
    do {								\
	(vertices)[0] = v_from_x_coord_x(xscale, x);			\
	if (likely(yInverted)) {						\
	    (vertices)[1] = v_from_x_coord_y_inverted(yscale, y);	\
	} else {							\
	    (vertices)[1] = v_from_x_coord_y(yscale, y);		\
	}								\
    } while(0)

#define glamor_set_normalize_tri_vcoords(xscale, yscale, vtx,		\
					 yInverted, vertices)		\
    do {								\
	glamor_set_normalize_one_vcoord(xscale, yscale,			\
					(vtx)[0], (vtx)[1],		\
					yInverted, vertices);		\
	glamor_set_normalize_one_vcoord(xscale, yscale,			\
					(vtx)[2], (vtx)[3],		\
					yInverted, vertices+2);		\
	glamor_set_normalize_one_vcoord(xscale, yscale,			\
					(vtx)[4], (vtx)[5],		\
					yInverted, vertices+4);		\
    } while(0)

#define glamor_set_tcoords_tri_strip(width, height, x1, y1, x2, y2,	\
				     yInverted, vertices)		\
    do {								\
	(vertices)[0] = (x1);						\
	(vertices)[2] = (x2);						\
	(vertices)[6] = (vertices)[2];					\
	(vertices)[4] = (vertices)[0];					\
	if (likely(yInverted)) {						\
	    (vertices)[1] = (y1);					\
	    (vertices)[7] = (y2);					\
	}								\
	else {								\
	    (vertices)[1] = height - (y2);				\
	    (vertices)[7] = height - (y1);				\
	}								\
	(vertices)[3] = (vertices)[1];					\
	(vertices)[5] = (vertices)[7];					\
    } while(0)

#define glamor_set_normalize_vcoords_ext(priv, xscale, yscale,		\
				     x1, y1, x2, y2,			\
                                     yInverted, vertices, stride)	\
  do {									\
    int fbo_x_off, fbo_y_off;						\
    /* vertices may be write-only, so we use following			\
     * temporary variable. */						\
    float _t0_, _t1_, _t2_, _t5_;					\
    pixmap_priv_get_fbo_off(priv, &fbo_x_off, &fbo_y_off);		\
    (vertices)[0] = _t0_ = v_from_x_coord_x(xscale, x1 + fbo_x_off);	\
    (vertices)[1 * stride] = _t2_ = v_from_x_coord_x(xscale,		\
					x2 + fbo_x_off);		\
    (vertices)[2 * stride] = _t2_;					\
    (vertices)[3 * stride] = _t0_;					\
    if (likely(yInverted)) {							\
      (vertices)[1] = _t1_ = v_from_x_coord_y_inverted(yscale,		\
				y1 + fbo_y_off);			\
      (vertices)[2 * stride + 1] = _t5_ =				\
			v_from_x_coord_y_inverted(yscale,		\
					y2 + fbo_y_off);		\
    }									\
    else {								\
      (vertices)[1] = _t1_ = v_from_x_coord_y(yscale, y1 + fbo_y_off);	\
      (vertices)[2 * stride + 1] = _t5_ = v_from_x_coord_y(yscale,	\
					y2 + fbo_y_off);		\
    }									\
    (vertices)[1 * stride + 1] = _t1_;					\
    (vertices)[3 * stride + 1] = _t5_;					\
  } while(0)


#define glamor_set_normalize_vcoords(priv, xscale, yscale,		\
				     x1, y1, x2, y2,			\
                                     yInverted, vertices)		\
  do {									\
	glamor_set_normalize_vcoords_ext(priv, xscale, yscale,		\
				     x1, y1, x2, y2,			\
                                     yInverted, vertices, 2);		\
  } while(0)

#define glamor_set_const_ext(params, nparam, vertices, nverts, stride)	\
    do {								\
	int _i_ = 0, _j_ = 0;						\
	for(; _i_ < nverts; _i_++) {					\
	    for(_j_ = 0; _j_ < nparam; _j_++) {				\
		vertices[stride*_i_ + _j_] = params[_j_];		\
	    }								\
	}								\
    } while(0)

#define glamor_set_normalize_vcoords_tri_strip(xscale, yscale,		\
					       x1, y1, x2, y2,		\
					       yInverted, vertices)	\
    do {								\
	(vertices)[0] = v_from_x_coord_x(xscale, x1);			\
	(vertices)[2] = v_from_x_coord_x(xscale, x2);			\
	(vertices)[6] = (vertices)[2];					\
	(vertices)[4] = (vertices)[0];					\
	if (likely(yInverted)) {						\
	    (vertices)[1] = v_from_x_coord_y_inverted(yscale, y1);	\
	    (vertices)[7] = v_from_x_coord_y_inverted(yscale, y2);	\
	}								\
	else {								\
	    (vertices)[1] = v_from_x_coord_y(yscale, y1);		\
	    (vertices)[7] = v_from_x_coord_y(yscale, y2);		\
	}								\
	(vertices)[3] = (vertices)[1];					\
	(vertices)[5] = (vertices)[7];					\
    } while(0)

#define glamor_set_normalize_pt(xscale, yscale, x, y,		\
                                yInverted, pt)			\
    do {							\
        (pt)[0] = t_from_x_coord_x(xscale, x);			\
        if (likely(yInverted)) {					\
            (pt)[1] = t_from_x_coord_y_inverted(yscale, y);	\
        } else {						\
            (pt)[1] = t_from_x_coord_y(yscale, y);		\
        }							\
    } while(0)

#define glamor_set_circle_centre(width, height, x, y,	\
				 yInverted, c)		\
    do {						\
        (c)[0] = (float)x;				\
        if (likely(yInverted)) {				\
            (c)[1] = (float)y;				\
        } else {					\
            (c)[1] = (float)height - (float)y;		\
        }						\
    } while(0)

inline static void
glamor_calculate_boxes_bound(BoxPtr bound, BoxPtr boxes, int nbox)
{
	int x_min, y_min;
	int x_max, y_max;
	int i;
	x_min = y_min = MAXSHORT;
	x_max = y_max = MINSHORT;
	for (i = 0; i < nbox; i++) {
		if (x_min > boxes[i].x1)
			x_min = boxes[i].x1;
		if (y_min > boxes[i].y1)
			y_min = boxes[i].y1;

		if (x_max < boxes[i].x2)
			x_max = boxes[i].x2;
		if (y_max < boxes[i].y2)
			y_max = boxes[i].y2;
	}
	bound->x1 = x_min;
	bound->y1 = y_min;
	bound->x2 = x_max;
	bound->y2 = y_max;
}

inline static void
glamor_translate_boxes(BoxPtr boxes, int nbox, int dx, int dy)
{
	int i;
	for (i = 0; i < nbox; i++) {
		boxes[i].x1 += dx;
		boxes[i].y1 += dy;
		boxes[i].x2 += dx;
		boxes[i].y2 += dy;
	}
}

static inline Bool
region_is_empty(pixman_region16_t *region)
{
	return region->data && region->data->numRects == 0;
}

#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
#endif

#define ALIGN(i,m)	(((i) + (m) - 1) & ~((m) - 1))
#define MIN(a,b)	((a) < (b) ? (a) : (b))
#define MAX(a,b)	((a) > (b) ? (a) : (b))

#define glamor_check_fbo_size(_glamor_,_w_, _h_)    ((_w_) > 0 && (_h_) > 0 \
                                                    && (_w_) <= _glamor_->max_fbo_size  \
                                                    && (_h_) <= _glamor_->max_fbo_size)

/* For 1bpp pixmap, we don't store it as texture. */
#define glamor_check_pixmap_fbo_depth(_depth_) (			\
						_depth_ == 8		\
						|| _depth_ == 15	\
						|| _depth_ == 16	\
						|| _depth_ == 24	\
						|| _depth_ == 30	\
						|| _depth_ == 32)

#define GLAMOR_PIXMAP_PRIV_IS_PICTURE(pixmap_priv) (pixmap_priv && pixmap_priv->base.is_picture == 1)
#define GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)    (pixmap_priv && pixmap_priv->base.gl_fbo == GLAMOR_FBO_NORMAL)
#define GLAMOR_PIXMAP_PRIV_HAS_FBO_DOWNLOADED(pixmap_priv)    (pixmap_priv && (pixmap_priv->base.gl_fbo == GLAMOR_FBO_DOWNLOADED))

/**
 * Borrow from uxa.
 */
static inline CARD32
format_for_depth(int depth)
{
	switch (depth) {
	case 1:
		return PICT_a1;
	case 4:
		return PICT_a4;
	case 8:
		return PICT_a8;
	case 15:
		return PICT_x1r5g5b5;
	case 16:
		return PICT_r5g6b5;
	default:
	case 24:
		return PICT_x8r8g8b8;
#if XORG_VERSION_CURRENT >= 10699900
	case 30:
		return PICT_x2r10g10b10;
#endif
	case 32:
		return PICT_a8r8g8b8;
	}
}

static inline void
gl_iformat_for_depth(int depth, GLenum * format)
{
	switch (depth) {
#ifndef GLAMOR_GLES2
	case 1:
	case 8:
		*format = GL_ALPHA;
		break;
#endif
	default:
		*format = GL_RGBA;
		break;
       }
}

static inline CARD32
format_for_pixmap(PixmapPtr pixmap)
{
	glamor_pixmap_private *pixmap_priv;
	PictFormatShort pict_format;

	pixmap_priv = glamor_get_pixmap_private(pixmap);
	if (GLAMOR_PIXMAP_PRIV_IS_PICTURE(pixmap_priv))
		pict_format = pixmap_priv->base.picture->format;
	else
		pict_format = format_for_depth(pixmap->drawable.depth);

	return pict_format;
}

#define REVERT_NONE       		0
#define REVERT_NORMAL     		1
#define REVERT_DOWNLOADING_A1		2
#define REVERT_UPLOADING_A1		3
#define REVERT_DOWNLOADING_2_10_10_10 	4
#define REVERT_UPLOADING_2_10_10_10 	5
#define REVERT_DOWNLOADING_1_5_5_5  	7
#define REVERT_UPLOADING_1_5_5_5    	8
#define REVERT_DOWNLOADING_10_10_10_2 	9
#define REVERT_UPLOADING_10_10_10_2 	10

#define SWAP_NONE_DOWNLOADING  	0
#define SWAP_DOWNLOADING  	1
#define SWAP_UPLOADING	  	2
#define SWAP_NONE_UPLOADING	3

/*
 * Map picture's format to the correct gl texture format and type.
 * no_alpha is used to indicate whehter we need to wire alpha to 1.
 *
 * Although opengl support A1/GL_BITMAP, we still don't use it
 * here, it seems that mesa has bugs when uploading a A1 bitmap.
 *
 * Return 0 if find a matched texture type. Otherwise return -1.
 **/
#ifndef GLAMOR_GLES2
static inline int
glamor_get_tex_format_type_from_pictformat(PictFormatShort format,
					   GLenum * tex_format,
					   GLenum * tex_type,
					   int *no_alpha,
					   int *revert,
					   int *swap_rb,
					   int is_upload)

{
	*no_alpha = 0;
	*revert = REVERT_NONE;
	*swap_rb = is_upload ? SWAP_NONE_UPLOADING : SWAP_NONE_DOWNLOADING;
	switch (format) {
	case PICT_a1:
		*tex_format = GL_ALPHA;
		*tex_type = GL_UNSIGNED_BYTE;
		*revert = is_upload ? REVERT_UPLOADING_A1 : REVERT_DOWNLOADING_A1;
		break;
	case PICT_b8g8r8x8:
		*no_alpha = 1;
	case PICT_b8g8r8a8:
		*tex_format = GL_BGRA;
		*tex_type = GL_UNSIGNED_INT_8_8_8_8;
		break;

	case PICT_x8r8g8b8:
		*no_alpha = 1;
	case PICT_a8r8g8b8:
		*tex_format = GL_BGRA;
		*tex_type = GL_UNSIGNED_INT_8_8_8_8_REV;
		break;
	case PICT_x8b8g8r8:
		*no_alpha = 1;
	case PICT_a8b8g8r8:
		*tex_format = GL_RGBA;
		*tex_type = GL_UNSIGNED_INT_8_8_8_8_REV;
		break;
	case PICT_x2r10g10b10:
		*no_alpha = 1;
	case PICT_a2r10g10b10:
		*tex_format = GL_BGRA;
		*tex_type = GL_UNSIGNED_INT_2_10_10_10_REV;
		break;
	case PICT_x2b10g10r10:
		*no_alpha = 1;
	case PICT_a2b10g10r10:
		*tex_format = GL_RGBA;
		*tex_type = GL_UNSIGNED_INT_2_10_10_10_REV;
		break;

	case PICT_r5g6b5:
		*tex_format = GL_RGB;
		*tex_type = GL_UNSIGNED_SHORT_5_6_5;
		break;
	case PICT_b5g6r5:
		*tex_format = GL_RGB;
		*tex_type = GL_UNSIGNED_SHORT_5_6_5_REV;
		break;
	case PICT_x1b5g5r5:
		*no_alpha = 1;
	case PICT_a1b5g5r5:
		*tex_format = GL_RGBA;
		*tex_type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
		break;

	case PICT_x1r5g5b5:
		*no_alpha = 1;
	case PICT_a1r5g5b5:
		*tex_format = GL_BGRA;
		*tex_type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
		break;
	case PICT_a8:
		*tex_format = GL_ALPHA;
		*tex_type = GL_UNSIGNED_BYTE;
		break;
	case PICT_x4r4g4b4:
		*no_alpha = 1;
	case PICT_a4r4g4b4:
		*tex_format = GL_BGRA;
		*tex_type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
		break;

	case PICT_x4b4g4r4:
		*no_alpha = 1;
	case PICT_a4b4g4r4:
		*tex_format = GL_RGBA;
		*tex_type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
		break;

	default:
		LogMessageVerb(X_INFO, 0,
			       "fail to get matched format for %x \n",
			       format);
		return -1;
	}
	return 0;
}

/* Currently, we use RGBA to represent all formats. */
inline static int cache_format(GLenum format)
{
	switch (format) {
	case GL_ALPHA:
		return 1;
	case GL_RGBA:
		return 0;
	default:
		return -1;
	}
}

#else
#define IS_LITTLE_ENDIAN  (IMAGE_BYTE_ORDER == LSBFirst)

static inline int
glamor_get_tex_format_type_from_pictformat(PictFormatShort format,
					   GLenum * tex_format,
					   GLenum * tex_type,
					   int *no_alpha,
					   int *revert,
					   int *swap_rb,
					   int is_upload)
{
	int need_swap_rb = 0;

	*no_alpha = 0;
	*revert = IS_LITTLE_ENDIAN ? REVERT_NONE : REVERT_NORMAL;

	switch (format) {
	case PICT_b8g8r8x8:
		*no_alpha = 1;
	case PICT_b8g8r8a8:
		*tex_format = GL_RGBA;
		*tex_type = GL_UNSIGNED_BYTE;
		need_swap_rb = 1;
		*revert = IS_LITTLE_ENDIAN ? REVERT_NORMAL : REVERT_NONE;
		break;

	case PICT_x8r8g8b8:
		*no_alpha = 1;
	case PICT_a8r8g8b8:
		*tex_format = GL_RGBA;
		*tex_type = GL_UNSIGNED_BYTE;
		need_swap_rb = 1;
		break;

	case PICT_x8b8g8r8:
		*no_alpha = 1;
	case PICT_a8b8g8r8:
		*tex_format = GL_RGBA;
		*tex_type = GL_UNSIGNED_BYTE;
		break;

	case PICT_x2r10g10b10:
		*no_alpha = 1;
	case PICT_a2r10g10b10:
		*tex_format = GL_RGBA;
		/* glReadPixmap doesn't support GL_UNSIGNED_INT_10_10_10_2.
		 * we have to use GL_UNSIGNED_BYTE and do the conversion in
		 * shader latter.*/
		*tex_type = GL_UNSIGNED_BYTE;
		if (is_upload == 1) {
			if (!IS_LITTLE_ENDIAN)
				*revert = REVERT_UPLOADING_10_10_10_2;
			else
				*revert = REVERT_UPLOADING_2_10_10_10;
		}
		else {
			if (!IS_LITTLE_ENDIAN) {
				*revert = REVERT_DOWNLOADING_10_10_10_2;
			}
			else {
				*revert = REVERT_DOWNLOADING_2_10_10_10;
			}
		}
		need_swap_rb = 1;

		break;

	case PICT_x2b10g10r10:
		*no_alpha = 1;
	case PICT_a2b10g10r10:
		*tex_format = GL_RGBA;
		*tex_type = GL_UNSIGNED_BYTE;
		if (is_upload == 1) {
			if (!IS_LITTLE_ENDIAN)
				*revert = REVERT_UPLOADING_10_10_10_2;
			else
				*revert = REVERT_UPLOADING_2_10_10_10;
		}
		else {
			if (!IS_LITTLE_ENDIAN) {
				*revert = REVERT_DOWNLOADING_10_10_10_2;
			}
			else {
				*revert = REVERT_DOWNLOADING_2_10_10_10;
			}
		}
		break;

	case PICT_r5g6b5:
		*tex_format = GL_RGB;
		*tex_type = GL_UNSIGNED_SHORT_5_6_5;
		*revert = IS_LITTLE_ENDIAN ? REVERT_NONE : REVERT_NORMAL;

		break;

	case PICT_b5g6r5:
		*tex_format = GL_RGB;
		*tex_type = GL_UNSIGNED_SHORT_5_6_5;
		need_swap_rb = IS_LITTLE_ENDIAN ? 1 : 0;;
		break;

	case PICT_x1b5g5r5:
		*no_alpha = 1;
	case PICT_a1b5g5r5:
		*tex_format = GL_RGBA;
		*tex_type = GL_UNSIGNED_SHORT_5_5_5_1;
		if (IS_LITTLE_ENDIAN) {
			*revert = is_upload ? REVERT_UPLOADING_1_5_5_5 : REVERT_DOWNLOADING_1_5_5_5;
		} else
			*revert = REVERT_NONE;
		break;

	case PICT_x1r5g5b5:
		*no_alpha = 1;
	case PICT_a1r5g5b5:
		*tex_format = GL_RGBA;
		*tex_type = GL_UNSIGNED_SHORT_5_5_5_1;
		if (IS_LITTLE_ENDIAN) {
			*revert = is_upload ? REVERT_UPLOADING_1_5_5_5 : REVERT_DOWNLOADING_1_5_5_5;
		} else
			*revert = REVERT_NONE;
		need_swap_rb = 1;
		break;

	case PICT_a1:
		*tex_format = GL_ALPHA;
		*tex_type = GL_UNSIGNED_BYTE;
		*revert = is_upload ? REVERT_UPLOADING_A1 : REVERT_DOWNLOADING_A1;
		break;

	case PICT_a8:
		*tex_format = GL_ALPHA;
		*tex_type = GL_UNSIGNED_BYTE;
		*revert = REVERT_NONE;
		break;

	case PICT_x4r4g4b4:
		*no_alpha = 1;
	case PICT_a4r4g4b4:
		*tex_format = GL_RGBA;
		*tex_type = GL_UNSIGNED_SHORT_4_4_4_4;
		*revert = IS_LITTLE_ENDIAN ? REVERT_NORMAL : REVERT_NONE;
		need_swap_rb = 1;
		break;

	case PICT_x4b4g4r4:
		*no_alpha = 1;
	case PICT_a4b4g4r4:
		*tex_format = GL_RGBA;
		*tex_type = GL_UNSIGNED_SHORT_4_4_4_4;
		*revert = IS_LITTLE_ENDIAN ? REVERT_NORMAL : REVERT_NONE;
		break;

	default:
		LogMessageVerb(X_INFO, 0,
			       "fail to get matched format for %x \n",
			       format);
		return -1;
	}

	if (need_swap_rb)
		*swap_rb = is_upload ? SWAP_UPLOADING : SWAP_DOWNLOADING;
	else
		*swap_rb = is_upload ? SWAP_NONE_UPLOADING : SWAP_NONE_DOWNLOADING;
	return 0;
}

inline static int cache_format(GLenum format)
{
	switch (format) {
	case GL_ALPHA:
		return 2;
	case GL_RGB:
		return 1;
	case GL_RGBA:
		return 0;
	default:
		return -1;
	}
}

#endif


static inline int
glamor_get_tex_format_type_from_pixmap(PixmapPtr pixmap,
				       GLenum * format,
				       GLenum * type,
				       int *no_alpha,
				       int *revert,
				       int *swap_rb,
				       int is_upload)
{
	glamor_pixmap_private *pixmap_priv;
	PictFormatShort pict_format;

	pixmap_priv = glamor_get_pixmap_private(pixmap);
	if (GLAMOR_PIXMAP_PRIV_IS_PICTURE(pixmap_priv))
		pict_format = pixmap_priv->base.picture->format;
	else
		pict_format = format_for_depth(pixmap->drawable.depth);

	return glamor_get_tex_format_type_from_pictformat(pict_format,
							  format, type,
							  no_alpha,
							  revert,
							  swap_rb,
							  is_upload);
}


/* borrowed from uxa */
static inline Bool
glamor_get_rgba_from_pixel(CARD32 pixel,
			   float *red,
			   float *green,
			   float *blue, float *alpha, CARD32 format)
{
	int rbits, bbits, gbits, abits;
	int rshift, bshift, gshift, ashift;

	rbits = PICT_FORMAT_R(format);
	gbits = PICT_FORMAT_G(format);
	bbits = PICT_FORMAT_B(format);
	abits = PICT_FORMAT_A(format);

	if (PICT_FORMAT_TYPE(format) == PICT_TYPE_A) {
		rshift = gshift = bshift = ashift = 0;
	} else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
		bshift = 0;
		gshift = bbits;
		rshift = gshift + gbits;
		ashift = rshift + rbits;
	} else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) {
		rshift = 0;
		gshift = rbits;
		bshift = gshift + gbits;
		ashift = bshift + bbits;
#if XORG_VERSION_CURRENT >= 10699900
	} else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) {
		ashift = 0;
		rshift = abits;
		if (abits == 0)
			rshift = PICT_FORMAT_BPP(format) - (rbits + gbits +
							    bbits);
		gshift = rshift + rbits;
		bshift = gshift + gbits;
#endif
	} else {
		return FALSE;
	}
#define COLOR_INT_TO_FLOAT(_fc_, _p_, _s_, _bits_)	\
  *_fc_ = (((_p_) >> (_s_)) & (( 1 << (_bits_)) - 1))	\
    / (float)((1<<(_bits_)) - 1)

	if (rbits)
		COLOR_INT_TO_FLOAT(red, pixel, rshift, rbits);
	else
		*red = 0;

	if (gbits)
		COLOR_INT_TO_FLOAT(green, pixel, gshift, gbits);
	else
		*green = 0;

	if (bbits)
		COLOR_INT_TO_FLOAT(blue, pixel, bshift, bbits);
	else
		*blue = 0;

	if (abits)
		COLOR_INT_TO_FLOAT(alpha, pixel, ashift, abits);
	else
		*alpha = 1;

	return TRUE;
}

inline static Bool glamor_pict_format_is_compatible(PictFormatShort pict_format, int depth)
{
	GLenum iformat;

	gl_iformat_for_depth(depth, &iformat);
	switch (iformat) {
		case GL_RGBA:
			return (pict_format == PICT_a8r8g8b8 || pict_format == PICT_x8r8g8b8);
		case GL_ALPHA:
			return (pict_format == PICT_a8);
		default:
			return FALSE;
	}
}

/* return TRUE if we can access this pixmap at DDX driver. */
inline static Bool glamor_ddx_fallback_check_pixmap(DrawablePtr drawable)
{
	PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
	glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
	return (!pixmap_priv
		|| (pixmap_priv->type == GLAMOR_TEXTURE_DRM
		    || pixmap_priv->type == GLAMOR_MEMORY
		    || pixmap_priv->type == GLAMOR_DRM_ONLY));
}

inline static Bool glamor_ddx_fallback_check_gc(GCPtr gc)
{
	PixmapPtr pixmap;
	if (!gc)
		return TRUE;
        switch (gc->fillStyle) {
        case FillStippled:
        case FillOpaqueStippled:
                pixmap = gc->stipple;
                break;
        case FillTiled:
                pixmap = gc->tile.pixmap;
                break;
	default:
		pixmap = NULL;
        }
	return (!pixmap || glamor_ddx_fallback_check_pixmap(&pixmap->drawable));
}
inline static Bool glamor_is_large_pixmap(PixmapPtr pixmap)
{
	glamor_pixmap_private *priv;

	priv = glamor_get_pixmap_private(pixmap);
	return (priv->type == GLAMOR_TEXTURE_LARGE);
}

inline static Bool glamor_is_large_picture(PicturePtr picture)
{
	PixmapPtr pixmap;

	if (picture->pDrawable) {
		pixmap = glamor_get_drawable_pixmap(picture->pDrawable);
		return glamor_is_large_pixmap(pixmap);
	}
	return FALSE;
}

inline static Bool glamor_tex_format_is_readable(GLenum format)
{
	return ((format == GL_RGBA || format == GL_RGB || format == GL_ALPHA));

}

static inline void _glamor_dump_pixmap_bits(PixmapPtr pixmap, int x, int y, int w, int h)
{
	int i,j;
	unsigned char * p = pixmap->devPrivate.ptr;
	int stride = pixmap->devKind;

	p = p + y * stride + x;

	for (i = 0; i < h; i++)
	{
		ErrorF("line %3d: ", i);
		for(j = 0; j < w; j++)
			ErrorF("%2d ", (p[j/8] & (1 << (j%8)))>>(j%8));
		p += stride;
		ErrorF("\n");
	}
}

static inline void _glamor_dump_pixmap_byte(PixmapPtr pixmap, int x, int y, int w, int h)
{
	int i,j;
	unsigned char * p = pixmap->devPrivate.ptr;
	int stride = pixmap->devKind;

	p = p + y * stride + x;

	for (i = 0; i < h; i++)
	{
		ErrorF("line %3d: ", i);
		for(j = 0; j < w; j++)
			ErrorF("%2x ", p[j]);
		p += stride;
		ErrorF("\n");
	}
}

static inline void _glamor_dump_pixmap_sword(PixmapPtr pixmap, int x, int y, int w, int h)
{
	int i,j;
	unsigned short * p = pixmap->devPrivate.ptr;
	int stride = pixmap->devKind / 2;

	p = p + y * stride + x;

	for (i = 0; i < h; i++)
	{
		ErrorF("line %3d: ", i);
		for(j = 0; j < w; j++)
			ErrorF("%2x ", p[j]);
		p += stride;
		ErrorF("\n");
	}
}

static inline void _glamor_dump_pixmap_word(PixmapPtr pixmap, int x, int y, int w, int h)
{
	int i,j;
	unsigned int * p = pixmap->devPrivate.ptr;
	int stride = pixmap->devKind / 4;

	p = p + y * stride + x;

	for (i = 0; i < h; i++)
	{
		ErrorF("line %3d: ", i);
		for(j = 0; j < w; j++)
			ErrorF("%2x ", p[j]);
		p += stride;
		ErrorF("\n");
	}
}

static inline void glamor_dump_pixmap(PixmapPtr pixmap, int x, int y, int w, int h)
{
	w = ((x + w) > pixmap->drawable.width) ? (pixmap->drawable.width - x) : w;
	h = ((y + h) > pixmap->drawable.height) ? (pixmap->drawable.height - y) : h;

	glamor_prepare_access(&pixmap->drawable, GLAMOR_ACCESS_RO);
	switch (pixmap->drawable.depth) {
	case 8:
		_glamor_dump_pixmap_byte(pixmap, x, y, w, h);
		break;
	case 15:
	case 16:
		_glamor_dump_pixmap_sword(pixmap, x, y, w, h);
		break;

	case 24:
	case 32:
		_glamor_dump_pixmap_word(pixmap, x, y, w, h);
		break;
	case 1:
		_glamor_dump_pixmap_bits(pixmap, x, y, w, h);
		break;
	default:
		ErrorF("dump depth %d, not implemented.\n", pixmap->drawable.depth);
	}
	glamor_finish_access(&pixmap->drawable, GLAMOR_ACCESS_RO);
}

static inline void _glamor_compare_pixmaps(PixmapPtr pixmap1, PixmapPtr pixmap2,
                                           int x, int y, int w, int h,
                                           PictFormatShort short_format,
                                           int all, int diffs)
{
	int i, j;
	unsigned char * p1 = pixmap1->devPrivate.ptr;
	unsigned char * p2 = pixmap2->devPrivate.ptr;
	int line_need_printed = 0;
	int test_code = 0xAABBCCDD;
	int little_endian = 0;
	unsigned char *p_test;
	int bpp = pixmap1->drawable.depth == 8 ? 1 : 4;
	int stride = pixmap1->devKind;

	assert(pixmap1->devKind == pixmap2->devKind);

	ErrorF("stride:%d, width:%d, height:%d\n", stride, w, h);

	p1 = p1 + y * stride + x;
	p2 = p2 + y * stride + x;

	if (all) {
		for (i = 0; i < h; i++) {
			ErrorF("line %3d: ", i);

			for (j = 0; j < stride; j++) {
				if (j % bpp == 0)
					ErrorF("[%d]%2x:%2x ", j / bpp, p1[j], p2[j]);
				else
					ErrorF("%2x:%2x ", p1[j], p2[j]);
			}

			p1 += stride;
			p2 += stride;
			ErrorF("\n");
		}
	} else {
		if (short_format == PICT_a8r8g8b8) {
			p_test = (unsigned char *) & test_code;
			little_endian = (*p_test == 0xDD);
			bpp = 4;

			for (i = 0; i < h; i++) {
				line_need_printed = 0;

				for (j = 0; j < stride; j++) {
					if (p1[j] != p2[j] && (p1[j] - p2[j] > diffs || p2[j] - p1[j] > diffs)) {
						if (line_need_printed) {
							if (little_endian) {
								switch (j % 4) {
									case 2:
										ErrorF("[%d]RED:%2x:%2x ", j / bpp, p1[j], p2[j]);
										break;
									case 1:
										ErrorF("[%d]GREEN:%2x:%2x ", j / bpp, p1[j], p2[j]);
										break;
									case 0:
										ErrorF("[%d]BLUE:%2x:%2x ", j / bpp, p1[j], p2[j]);
										break;
									case 3:
										ErrorF("[%d]Alpha:%2x:%2x ", j / bpp, p1[j], p2[j]);
										break;
								}
							} else {
								switch (j % 4) {
									case 1:
										ErrorF("[%d]RED:%2x:%2x ", j / bpp, p1[j], p2[j]);
										break;
									case 2:
										ErrorF("[%d]GREEN:%2x:%2x ", j / bpp, p1[j], p2[j]);
										break;
									case 3:
										ErrorF("[%d]BLUE:%2x:%2x ", j / bpp, p1[j], p2[j]);
										break;
									case 0:
										ErrorF("[%d]Alpha:%2x:%2x ", j / bpp, p1[j], p2[j]);
										break;
								}
							}
						} else {
							line_need_printed = 1;
							j = -1;
							ErrorF("line %3d: ", i);
							continue;
						}
					}
				}

				p1 += stride;
				p2 += stride;
				ErrorF("\n");
			}
		} //more format can be added here.
		else { // the default format, just print.
			for (i = 0; i < h; i++) {
				line_need_printed = 0;

				for (j = 0; j < stride; j++) {
					if (p1[j] != p2[j]) {
						if (line_need_printed) {
							ErrorF("[%d]%2x:%2x ", j / bpp, p1[j], p2[j]);
						} else {
							line_need_printed = 1;
							j = -1;
							ErrorF("line %3d: ", i);
							continue;
						}
					}
				}

				p1 += stride;
				p2 += stride;
				ErrorF("\n");
			}
		}
	}
}

static inline void glamor_compare_pixmaps(PixmapPtr pixmap1, PixmapPtr pixmap2,
                                          int x, int y, int w, int h, int all, int diffs)
{
	assert(pixmap1->drawable.depth == pixmap2->drawable.depth);

	glamor_prepare_access(&pixmap1->drawable, GLAMOR_ACCESS_RO);
	glamor_prepare_access(&pixmap2->drawable, GLAMOR_ACCESS_RO);

	_glamor_compare_pixmaps(pixmap1, pixmap2, x, y, w, h, -1, all, diffs);

	glamor_finish_access(&pixmap1->drawable, GLAMOR_ACCESS_RO);
	glamor_finish_access(&pixmap2->drawable, GLAMOR_ACCESS_RO);
}

/* This function is used to compare two pictures.
   If the picture has no drawable, we use fb functions to generate it. */
static inline void glamor_compare_pictures( ScreenPtr screen,
                                            PicturePtr fst_picture,
                                            PicturePtr snd_picture,
                                            int x_source, int y_source,
                                            int width, int height,
                                            int all, int diffs)
{
	PixmapPtr fst_pixmap;
	PixmapPtr snd_pixmap;
	int fst_generated, snd_generated;
	int error;
	int fst_type = -1;
	int snd_type = -1; // -1 represent has drawable.

	if (fst_picture->format != snd_picture->format) {
		ErrorF("Different picture format can not compare!\n");
		return;
	}

	if (!fst_picture->pDrawable) {
		fst_type = fst_picture->pSourcePict->type;
	}

	if (!snd_picture->pDrawable) {
		snd_type = snd_picture->pSourcePict->type;
	}

	if ((fst_type != -1) && (snd_type != -1) && (fst_type != snd_type)) {
		ErrorF("Different picture type will never be same!\n");
		return;
	}

	fst_generated = snd_generated = 0;

	if (!fst_picture->pDrawable) {
		PicturePtr pixman_pic;
		PixmapPtr pixmap = NULL;
		PictFormatShort format;

		format = fst_picture->format;

		pixmap = glamor_create_pixmap(screen,
		                              width, height,
		                              PIXMAN_FORMAT_DEPTH(format),
		                              GLAMOR_CREATE_PIXMAP_CPU);

		pixman_pic = CreatePicture(0,
		                           &pixmap->drawable,
		                           PictureMatchFormat(screen,
		                               PIXMAN_FORMAT_DEPTH(format), format),
		                           0, 0, serverClient, &error);

		fbComposite(PictOpSrc, fst_picture, NULL, pixman_pic,
		            x_source, y_source,
		            0, 0,
		            0, 0,
		            width, height);

		glamor_destroy_pixmap(pixmap);

		fst_picture = pixman_pic;
		fst_generated = 1;
	}

	if (!snd_picture->pDrawable) {
		PicturePtr pixman_pic;
		PixmapPtr pixmap = NULL;
		PictFormatShort format;

		format = snd_picture->format;

		pixmap = glamor_create_pixmap(screen,
		                              width, height,
		                              PIXMAN_FORMAT_DEPTH(format),
		                              GLAMOR_CREATE_PIXMAP_CPU);

		pixman_pic = CreatePicture(0,
		                           &pixmap->drawable,
		                           PictureMatchFormat(screen,
		                               PIXMAN_FORMAT_DEPTH(format), format),
		                           0, 0, serverClient, &error);

		fbComposite(PictOpSrc, snd_picture, NULL, pixman_pic,
		            x_source, y_source,
		            0, 0,
		            0, 0,
		            width, height);

		glamor_destroy_pixmap(pixmap);

		snd_picture = pixman_pic;
		snd_generated = 1;
	}

	fst_pixmap = glamor_get_drawable_pixmap(fst_picture->pDrawable);
	snd_pixmap = glamor_get_drawable_pixmap(snd_picture->pDrawable);

	if (fst_pixmap->drawable.depth != snd_pixmap->drawable.depth) {
		if (fst_generated)
			glamor_destroy_picture(fst_picture);
		if (snd_generated)
			glamor_destroy_picture(snd_picture);

		ErrorF("Different pixmap depth can not compare!\n");
		return;
	}

	glamor_prepare_access(&fst_pixmap->drawable, GLAMOR_ACCESS_RO);
	glamor_prepare_access(&snd_pixmap->drawable, GLAMOR_ACCESS_RO);

	if ((fst_type == SourcePictTypeLinear) ||
	     (fst_type == SourcePictTypeRadial) ||
	     (fst_type == SourcePictTypeConical) ||
	     (snd_type == SourcePictTypeLinear) ||
	     (snd_type == SourcePictTypeRadial) ||
	     (snd_type == SourcePictTypeConical)) {
		x_source = y_source = 0;
	}

	_glamor_compare_pixmaps(fst_pixmap, snd_pixmap,
	                        x_source, y_source,
	                        width, height,
	                        fst_picture->format, all, diffs);

	glamor_finish_access(&fst_pixmap->drawable, GLAMOR_ACCESS_RO);
	glamor_finish_access(&snd_pixmap->drawable, GLAMOR_ACCESS_RO);

	if (fst_generated)
		glamor_destroy_picture(fst_picture);
	if (snd_generated)
		glamor_destroy_picture(snd_picture);

	return;
}

#ifdef __i386__
static inline unsigned long __fls(unsigned long x)
{
        asm("bsr %1,%0"
            : "=r" (x)
            : "rm" (x));
        return x;
}
#else
static inline unsigned long __fls(unsigned long x)
{
   int n;

   if (x == 0) return(0);
   n = 0;
   if (x <= 0x0000FFFF) {n = n +16; x = x <<16;}
   if (x <= 0x00FFFFFF) {n = n + 8; x = x << 8;}
   if (x <= 0x0FFFFFFF) {n = n + 4; x = x << 4;}
   if (x <= 0x3FFFFFFF) {n = n + 2; x = x << 2;}
   if (x <= 0x7FFFFFFF) {n = n + 1;}
   return 31 - n;
}
#endif

static inline void glamor_make_current(ScreenPtr screen)
{
	glamor_egl_make_current(screen);
}

static inline void glamor_restore_current(ScreenPtr screen)
{
	glamor_egl_restore_context(screen);
}

#ifdef GLX_USE_SHARED_DISPATCH
static inline glamor_gl_dispatch *
glamor_get_dispatch(glamor_screen_private *glamor_priv)
{
	if (glamor_priv->flags & GLAMOR_USE_EGL_SCREEN)
		glamor_make_current(glamor_priv->screen);

	return &glamor_priv->_dispatch;
}

static inline void
glamor_put_dispatch(glamor_screen_private *glamor_priv)
{
	if (glamor_priv->flags & GLAMOR_USE_EGL_SCREEN)
		glamor_restore_current(glamor_priv->screen);
}
#else
#warning "Indirect GLX may be broken, need to implement context switch."
static inline glamor_gl_dispatch *
glamor_get_dispatch(glamor_screen_private *glamor_priv)
{
	return &glamor_priv->_dispatch;
}

static inline void
glamor_put_dispatch(glamor_screen_private *glamor_priv)
{
}

#endif

#endif
