1 /*
2  * Copyright © 2009 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  *
23  * Authors:
24  *    Zhigang Gong <zhigang.gong@linux.intel.com>
25  *
26  */
27 
28 #ifndef GLAMOR_PRIV_H
29 #error This file can only be included by glamor_priv.h
30 #endif
31 
32 #ifndef __GLAMOR_UTILS_H__
33 #define __GLAMOR_UTILS_H__
34 
35 #include "glamor_prepare.h"
36 #include "mipict.h"
37 
38 #define v_from_x_coord_x(_xscale_, _x_)          ( 2 * (_x_) * (_xscale_) - 1.0)
39 #define v_from_x_coord_y(_yscale_, _y_)          (2 * (_y_) * (_yscale_) - 1.0)
40 #define t_from_x_coord_x(_xscale_, _x_)          ((_x_) * (_xscale_))
41 #define t_from_x_coord_y(_yscale_, _y_)          ((_y_) * (_yscale_))
42 
43 #define pixmap_priv_get_dest_scale(pixmap, _pixmap_priv_, _pxscale_, _pyscale_) \
44   do {                                                                   \
45     int _w_,_h_;                                                         \
46     PIXMAP_PRIV_GET_ACTUAL_SIZE(pixmap, _pixmap_priv_, _w_, _h_);        \
47     *(_pxscale_) = 1.0 / _w_;                                            \
48     *(_pyscale_) = 1.0 / _h_;                                            \
49    } while(0)
50 
51 #define pixmap_priv_get_scale(_pixmap_priv_, _pxscale_, _pyscale_)	\
52    do {									\
53     *(_pxscale_) = 1.0 / (_pixmap_priv_)->fbo->width;			\
54     *(_pyscale_) = 1.0 / (_pixmap_priv_)->fbo->height;			\
55   } while(0)
56 
57 #define PIXMAP_PRIV_GET_ACTUAL_SIZE(pixmap, priv, w, h)          \
58   do {								\
59 	if (_X_UNLIKELY(glamor_pixmap_priv_is_large(priv))) {	\
60 		w = priv->box.x2 - priv->box.x1;	\
61 		h = priv->box.y2 - priv->box.y1;	\
62 	} else {						\
63 		w = (pixmap)->drawable.width;		\
64 		h = (pixmap)->drawable.height;		\
65 	}							\
66   } while(0)
67 
68 #define glamor_pixmap_fbo_fix_wh_ratio(wh, pixmap, priv)         \
69   do {								\
70 	int actual_w, actual_h;					\
71 	PIXMAP_PRIV_GET_ACTUAL_SIZE(pixmap, priv, actual_w, actual_h);	\
72 	wh[0] = (float)priv->fbo->width / actual_w;	\
73 	wh[1] = (float)priv->fbo->height / actual_h;	\
74 	wh[2] = 1.0 / priv->fbo->width;			\
75 	wh[3] = 1.0 / priv->fbo->height;			\
76   } while(0)
77 
78 #define pixmap_priv_get_fbo_off(_priv_, _xoff_, _yoff_)		\
79    do {								\
80         if (_X_UNLIKELY(_priv_ && glamor_pixmap_priv_is_large(_priv_))) { \
81 		*(_xoff_) = - (_priv_)->box.x1;	\
82 		*(_yoff_) = - (_priv_)->box.y1;	\
83 	} else {						\
84 		*(_xoff_) = 0;					\
85 		*(_yoff_) = 0;					\
86 	}							\
87    } while(0)
88 
89 #define xFixedToFloat(_val_) ((float)xFixedToInt(_val_)			\
90 			      + ((float)xFixedFrac(_val_) / 65536.0))
91 
92 #define glamor_picture_get_matrixf(_picture_, _matrix_)			\
93   do {									\
94     int _i_;								\
95     if ((_picture_)->transform)						\
96       {									\
97 	for(_i_ = 0; _i_ < 3; _i_++)					\
98 	  {								\
99 	    (_matrix_)[_i_ * 3 + 0] =					\
100 	      xFixedToFloat((_picture_)->transform->matrix[_i_][0]);	\
101 	    (_matrix_)[_i_ * 3 + 1] =					\
102 	      xFixedToFloat((_picture_)->transform->matrix[_i_][1]);	\
103 	    (_matrix_)[_i_ * 3 + 2] = \
104 	      xFixedToFloat((_picture_)->transform->matrix[_i_][2]);	\
105 	  }								\
106       }									\
107   }  while(0)
108 
109 #define fmod(x, w)		(x - w * floor((float)x/w))
110 
111 #define fmodulus(x, w, c)	do {c = fmod(x, w);		\
112 				    c = c >= 0 ? c : c + w;}	\
113 				while(0)
114 /* @x: is current coord
115  * @x2: is the right/bottom edge
116  * @w: is current width or height
117  * @odd: is output value, 0 means we are in an even region, 1 means we are in a
118  * odd region.
119  * @c: is output value, equal to x mod w. */
120 #define fodd_repeat_mod(x, x2, w, odd, c)	\
121   do {						\
122 	float shift;				\
123 	fmodulus((x), w, c); 			\
124 	shift = fabs((x) - (c));		\
125 	shift = floor(fabs(round(shift)) / w);	\
126 	odd = (int)shift & 1;			\
127 	if (odd && (((x2 % w) == 0) &&		\
128 	    round(fabs(x)) == x2))		\
129 		odd = 0;			\
130   } while(0)
131 
132 /* @txy: output value, is the corrected coords.
133  * @xy: input coords to be fixed up.
134  * @cd: xy mod wh, is a input value.
135  * @wh: current width or height.
136  * @bxy1,bxy2: current box edge's x1/x2 or y1/y2
137  *
138  * case 1:
139  *  ----------
140  *  |  *     |
141  *  |        |
142  *  ----------
143  *  tx = (c - x1) mod w
144  *
145  *  case 2:
146  *     ---------
147  *  *  |       |
148  *     |       |
149  *     ---------
150  *   tx = - (c - (x1 mod w))
151  *
152  *   case 3:
153  *
154  *   ----------
155  *   |        |  *
156  *   |        |
157  *   ----------
158  *   tx = ((x2 mod x) - c) + (x2 - x1)
159  **/
160 #define __glamor_repeat_reflect_fixup(txy, xy,		\
161 				cd, wh, bxy1, bxy2)	\
162   do {							\
163 	cd = wh - cd;					\
164 	if ( xy >= bxy1 && xy < bxy2) {			\
165 		cd = cd - bxy1;				\
166 		fmodulus(cd, wh, txy);			\
167 	} else	if (xy < bxy1) {			\
168 		float bxy1_mod;				\
169 		fmodulus(bxy1, wh, bxy1_mod);		\
170 		txy = -(cd - bxy1_mod);			\
171 	}						\
172 	else if (xy >= bxy2)	{			\
173 		float bxy2_mod;				\
174 		fmodulus(bxy2, wh, bxy2_mod);		\
175 		if (bxy2_mod == 0)			\
176 			bxy2_mod = wh;			\
177 		txy = (bxy2_mod - cd) + bxy2 - bxy1;	\
178 	} else {assert(0); txy = 0;}			\
179   } while(0)
180 
181 #define _glamor_repeat_reflect_fixup(txy, xy, cd, odd,	\
182 				     wh, bxy1, bxy2)	\
183   do {							\
184 	if (odd) {					\
185 		__glamor_repeat_reflect_fixup(txy, xy, 	\
186 			cd, wh, bxy1, bxy2);		\
187 	} else						\
188 		txy = xy - bxy1;			\
189   } while(0)
190 
191 #define _glamor_get_reflect_transform_coords(pixmap, priv, repeat_type,	\
192 					    tx1, ty1, 		\
193 				            _x1_, _y1_)		\
194   do {								\
195 	int odd_x, odd_y;					\
196 	float c, d;						\
197 	fodd_repeat_mod(_x1_,priv->box.x2,			\
198 		    (pixmap)->drawable.width,		\
199 		    odd_x, c);					\
200 	fodd_repeat_mod(_y1_,	priv->box.y2,			\
201 		    (pixmap)->drawable.height,		\
202 		    odd_y, d);					\
203 	DEBUGF("c %f d %f oddx %d oddy %d \n",			\
204 		c, d, odd_x, odd_y);				\
205 	DEBUGF("x2 %d x1 %d fbo->width %d \n", priv->box.x2,	\
206 		priv->box.x1, priv->fbo->width);		\
207 	DEBUGF("y2 %d y1 %d fbo->height %d \n", priv->box.y2, 	\
208 		priv->box.y1, priv->fbo->height);		\
209 	_glamor_repeat_reflect_fixup(tx1, _x1_, c, odd_x,	\
210 		(pixmap)->drawable.width,		\
211 		priv->box.x1, priv->box.x2);			\
212 	_glamor_repeat_reflect_fixup(ty1, _y1_, d, odd_y,	\
213 		(pixmap)->drawable.height,		\
214 		priv->box.y1, priv->box.y2);			\
215    } while(0)
216 
217 #define _glamor_get_repeat_coords(pixmap, priv, repeat_type, tx1,	\
218 				  ty1, tx2, ty2,		\
219 				  _x1_, _y1_, _x2_,		\
220 				  _y2_, c, d, odd_x, odd_y)	\
221   do {								\
222 	if (repeat_type == RepeatReflect) {			\
223 		DEBUGF("x1 y1 %d %d\n",				\
224 			_x1_, _y1_ );				\
225 		DEBUGF("width %d box.x1 %d \n",			\
226 		       (pixmap)->drawable.width,	\
227 		       priv->box.x1);				\
228 		if (odd_x) {					\
229 			c = (pixmap)->drawable.width	\
230 				- c;				\
231 			tx1 = c - priv->box.x1;			\
232 			tx2 = tx1 - ((_x2_) - (_x1_));		\
233 		} else {					\
234 			tx1 = c - priv->box.x1;			\
235 			tx2 = tx1 + ((_x2_) - (_x1_));		\
236 		}						\
237 		if (odd_y){					\
238 			d = (pixmap)->drawable.height\
239 			    - d;				\
240 			ty1 = d - priv->box.y1;			\
241 			ty2 = ty1 - ((_y2_) - (_y1_));		\
242 		} else {					\
243 			ty1 = d - priv->box.y1;			\
244 			ty2 = ty1 + ((_y2_) - (_y1_));		\
245 		}						\
246 	} else { /* RepeatNormal*/				\
247 		tx1 = (c - priv->box.x1);  			\
248 		ty1 = (d - priv->box.y1);			\
249 		tx2 = tx1 + ((_x2_) - (_x1_));			\
250 		ty2 = ty1 + ((_y2_) - (_y1_));			\
251 	}							\
252    } while(0)
253 
254 /* _x1_ ... _y2_ may has fractional. */
255 #define glamor_get_repeat_transform_coords(pixmap, priv, repeat_type, tx1, \
256 					   ty1, _x1_, _y1_)		\
257   do {									\
258 	DEBUGF("width %d box.x1 %d x2 %d y1 %d y2 %d\n",		\
259 		(pixmap)->drawable.width,			\
260 		priv->box.x1, priv->box.x2, priv->box.y1,		\
261 		priv->box.y2);						\
262 	DEBUGF("x1 %f y1 %f \n", _x1_, _y1_);				\
263 	if (repeat_type != RepeatReflect) {				\
264 		tx1 = _x1_ - priv->box.x1;				\
265 		ty1 = _y1_ - priv->box.y1;				\
266 	} else			\
267                 _glamor_get_reflect_transform_coords(pixmap, priv, repeat_type, \
268 				  tx1, ty1, 				\
269 				  _x1_, _y1_);				\
270 	DEBUGF("tx1 %f ty1 %f \n", tx1, ty1);				\
271    } while(0)
272 
273 /* _x1_ ... _y2_ must be integer. */
274 #define glamor_get_repeat_coords(pixmap, priv, repeat_type, tx1,		\
275 				 ty1, tx2, ty2, _x1_, _y1_, _x2_,	\
276 				 _y2_) 					\
277   do {									\
278 	int c, d;							\
279 	int odd_x = 0, odd_y = 0;					\
280 	DEBUGF("width %d box.x1 %d x2 %d y1 %d y2 %d\n",		\
281 		(pixmap)->drawable.width,			\
282 		priv->box.x1, priv->box.x2,				\
283 		priv->box.y1, priv->box.y2);				\
284 	modulus((_x1_), (pixmap)->drawable.width, c); 	\
285 	modulus((_y1_), (pixmap)->drawable.height, d);	\
286 	DEBUGF("c %d d %d \n", c, d);					\
287 	if (repeat_type == RepeatReflect) {				\
288 		odd_x = abs((_x1_ - c)					\
289                             / ((pixmap)->drawable.width)) & 1;            \
290 		odd_y = abs((_y1_ - d)					\
291                             / ((pixmap)->drawable.height)) & 1;           \
292 	}								\
293 	_glamor_get_repeat_coords(pixmap, priv, repeat_type, tx1, ty1, tx2, ty2, \
294 				  _x1_, _y1_, _x2_, _y2_, c, d,		\
295 				  odd_x, odd_y);			\
296    } while(0)
297 
298 #define glamor_transform_point(matrix, tx, ty, x, y)			\
299   do {									\
300     int _i_;								\
301     float _result_[4];							\
302     for (_i_ = 0; _i_ < 3; _i_++) {					\
303       _result_[_i_] = (matrix)[_i_ * 3] * (x) + (matrix)[_i_ * 3 + 1] * (y)	\
304 	+ (matrix)[_i_ * 3 + 2];					\
305     }									\
306     tx = _result_[0] / _result_[2];					\
307     ty = _result_[1] / _result_[2];					\
308   } while(0)
309 
310 #define _glamor_set_normalize_tpoint(xscale, yscale, _tx_, _ty_,	\
311 				     texcoord)                          \
312   do {									\
313 	(texcoord)[0] = t_from_x_coord_x(xscale, _tx_);			\
314         (texcoord)[1] = t_from_x_coord_y(yscale, _ty_);                 \
315         DEBUGF("normalized point tx %f ty %f \n", (texcoord)[0],	\
316 		(texcoord)[1]);						\
317   } while(0)
318 
319 #define glamor_set_transformed_point(priv, matrix, xscale,              \
320 				     yscale, texcoord,			\
321                                      x, y)				\
322   do {									\
323     float tx, ty;							\
324     int fbo_x_off, fbo_y_off;						\
325     pixmap_priv_get_fbo_off(priv, &fbo_x_off, &fbo_y_off);		\
326     glamor_transform_point(matrix, tx, ty, x, y);			\
327     DEBUGF("tx %f ty %f fbooff %d %d \n",				\
328 	    tx, ty, fbo_x_off, fbo_y_off);				\
329 									\
330     tx += fbo_x_off;							\
331     ty += fbo_y_off;							\
332     (texcoord)[0] = t_from_x_coord_x(xscale, tx);			\
333     (texcoord)[1] = t_from_x_coord_y(yscale, ty);                       \
334     DEBUGF("normalized tx %f ty %f \n", (texcoord)[0], (texcoord)[1]);	\
335   } while(0)
336 
337 #define glamor_set_transformed_normalize_tcoords_ext( priv,		\
338 						  matrix,		\
339 						  xscale,		\
340 						  yscale,		\
341                                                   tx1, ty1, tx2, ty2,   \
342                                                   texcoords,		\
343 						  stride)		\
344   do {									\
345     glamor_set_transformed_point(priv, matrix, xscale, yscale,		\
346 				 texcoords, tx1, ty1);                  \
347     glamor_set_transformed_point(priv, matrix, xscale, yscale,		\
348 				 texcoords + 1 * stride, tx2, ty1);     \
349     glamor_set_transformed_point(priv, matrix, xscale, yscale,		\
350 				 texcoords + 2 * stride, tx2, ty2);     \
351     glamor_set_transformed_point(priv, matrix, xscale, yscale,		\
352 				 texcoords + 3 * stride, tx1, ty2);     \
353   } while (0)
354 
355 #define glamor_set_repeat_transformed_normalize_tcoords_ext(pixmap, priv, \
356 							 repeat_type,	\
357 							 matrix,	\
358 							 xscale,	\
359 							 yscale,	\
360 							 _x1_, _y1_,	\
361 							 _x2_, _y2_,   	\
362 							 texcoords,	\
363 							 stride)	\
364   do {									\
365     if (_X_LIKELY(glamor_pixmap_priv_is_small(priv))) {		\
366 	glamor_set_transformed_normalize_tcoords_ext(priv, matrix, xscale,	\
367 						 yscale, _x1_, _y1_,	\
368 						 _x2_, _y2_,	\
369 						 texcoords, stride);	\
370     } else {								\
371     float tx1, ty1, tx2, ty2, tx3, ty3, tx4, ty4;			\
372     float ttx1, tty1, ttx2, tty2, ttx3, tty3, ttx4, tty4;		\
373     DEBUGF("original coords %d %d %d %d\n", _x1_, _y1_, _x2_, _y2_);	\
374     glamor_transform_point(matrix, tx1, ty1, _x1_, _y1_);		\
375     glamor_transform_point(matrix, tx2, ty2, _x2_, _y1_);		\
376     glamor_transform_point(matrix, tx3, ty3, _x2_, _y2_);		\
377     glamor_transform_point(matrix, tx4, ty4, _x1_, _y2_);		\
378     DEBUGF("transformed %f %f %f %f %f %f %f %f\n",			\
379 	   tx1, ty1, tx2, ty2, tx3, ty3, tx4, ty4);			\
380     glamor_get_repeat_transform_coords(pixmap, priv, repeat_type, \
381 				       ttx1, tty1, 			\
382 				       tx1, ty1);			\
383     glamor_get_repeat_transform_coords(pixmap, priv, repeat_type, 	\
384 				       ttx2, tty2, 			\
385 				       tx2, ty2);			\
386     glamor_get_repeat_transform_coords(pixmap, priv, repeat_type, 	\
387 				       ttx3, tty3, 			\
388 				       tx3, ty3);			\
389     glamor_get_repeat_transform_coords(pixmap, priv, repeat_type, 	\
390 				       ttx4, tty4, 			\
391 				       tx4, ty4);			\
392     DEBUGF("repeat transformed %f %f %f %f %f %f %f %f\n", ttx1, tty1, 	\
393 	    ttx2, tty2,	ttx3, tty3, ttx4, tty4);			\
394     _glamor_set_normalize_tpoint(xscale, yscale, ttx1, tty1,		\
395 				 texcoords);			\
396     _glamor_set_normalize_tpoint(xscale, yscale, ttx2, tty2,		\
397 				 texcoords + 1 * stride);	\
398     _glamor_set_normalize_tpoint(xscale, yscale, ttx3, tty3,		\
399 				 texcoords + 2 * stride);	\
400     _glamor_set_normalize_tpoint(xscale, yscale, ttx4, tty4,		\
401 				 texcoords + 3 * stride);	\
402    }									\
403   } while (0)
404 
405 #define glamor_set_repeat_transformed_normalize_tcoords( pixmap,        \
406                                                          priv,          \
407 							 repeat_type,	\
408 							 matrix,	\
409 							 xscale,	\
410 							 yscale,	\
411 							 _x1_, _y1_,	\
412 							 _x2_, _y2_,   	\
413 							 texcoords)	\
414   do {									\
415       glamor_set_repeat_transformed_normalize_tcoords_ext( pixmap,      \
416                                                            priv,	\
417 							 repeat_type,	\
418 							 matrix,	\
419 							 xscale,	\
420 							 yscale,	\
421 							 _x1_, _y1_,	\
422 							 _x2_, _y2_,   	\
423 							 texcoords,	\
424 							 2);	\
425   } while (0)
426 
427 #define _glamor_set_normalize_tcoords(xscale, yscale, tx1,		\
428 				      ty1, tx2, ty2,			\
429 				      vertices, stride)                 \
430   do {									\
431     /* vertices may be write-only, so we use following			\
432      * temporary variable. */ 						\
433     float _t0_, _t1_, _t2_, _t5_;					\
434     (vertices)[0] = _t0_ = t_from_x_coord_x(xscale, tx1);		\
435     (vertices)[1 * stride] = _t2_ = t_from_x_coord_x(xscale, tx2);	\
436     (vertices)[2 * stride] = _t2_;					\
437     (vertices)[3 * stride] = _t0_;					\
438     (vertices)[1] = _t1_ = t_from_x_coord_y(yscale, ty1);               \
439     (vertices)[2 * stride + 1] = _t5_ = t_from_x_coord_y(yscale, ty2);  \
440     (vertices)[1 * stride + 1] = _t1_;					\
441     (vertices)[3 * stride + 1] = _t5_;					\
442   } while(0)
443 
444 #define glamor_set_normalize_tcoords_ext(priv, xscale, yscale,		\
445 				     x1, y1, x2, y2,			\
446                                      vertices, stride)	\
447   do {									\
448      if (_X_UNLIKELY(glamor_pixmap_priv_is_large(priv))) {		\
449 	float tx1, tx2, ty1, ty2;					\
450 	int fbo_x_off, fbo_y_off;					\
451 	pixmap_priv_get_fbo_off(priv, &fbo_x_off, &fbo_y_off);		\
452 	tx1 = x1 + fbo_x_off; 						\
453 	tx2 = x2 + fbo_x_off;						\
454 	ty1 = y1 + fbo_y_off;						\
455 	ty2 = y2 + fbo_y_off;						\
456 	_glamor_set_normalize_tcoords(xscale, yscale, tx1, ty1,		\
457                                       tx2, ty2, vertices,               \
458 				   stride);				\
459      } else								\
460 	_glamor_set_normalize_tcoords(xscale, yscale, x1, y1,		\
461                                       x2, y2, vertices, stride);        \
462  } while(0)
463 
464 #define glamor_set_repeat_normalize_tcoords_ext(pixmap, priv, repeat_type, \
465 					    xscale, yscale,		\
466 					    _x1_, _y1_, _x2_, _y2_,	\
467 	                                    vertices, stride)		\
468   do {									\
469      if (_X_UNLIKELY(glamor_pixmap_priv_is_large(priv))) {		\
470 	float tx1, tx2, ty1, ty2;					\
471 	if (repeat_type == RepeatPad) {					\
472 		tx1 = _x1_ - priv->box.x1;			        \
473 		ty1 = _y1_ - priv->box.y1;			        \
474 		tx2 = tx1 + ((_x2_) - (_x1_));				\
475 		ty2 = ty1 + ((_y2_) - (_y1_));				\
476 	} else {							\
477             glamor_get_repeat_coords(pixmap, priv, repeat_type,         \
478 				 tx1, ty1, tx2, ty2,			\
479 				 _x1_, _y1_, _x2_, _y2_);		\
480 	}								\
481 	_glamor_set_normalize_tcoords(xscale, yscale, tx1, ty1,		\
482                                       tx2, ty2, vertices,               \
483 				   stride);				\
484      } else								\
485 	_glamor_set_normalize_tcoords(xscale, yscale, _x1_, _y1_,	\
486                                       _x2_, _y2_, vertices,             \
487 				   stride);				\
488  } while(0)
489 
490 #define glamor_set_normalize_tcoords_tri_stripe(xscale, yscale,		\
491 						x1, y1, x2, y2,		\
492 						vertices)               \
493     do {								\
494 	(vertices)[0] = t_from_x_coord_x(xscale, x1);			\
495 	(vertices)[2] = t_from_x_coord_x(xscale, x2);			\
496 	(vertices)[6] = (vertices)[2];					\
497 	(vertices)[4] = (vertices)[0];					\
498         (vertices)[1] = t_from_x_coord_y(yscale, y1);                   \
499         (vertices)[7] = t_from_x_coord_y(yscale, y2);                   \
500 	(vertices)[3] = (vertices)[1];					\
501 	(vertices)[5] = (vertices)[7];					\
502     } while(0)
503 
504 #define glamor_set_tcoords_tri_strip(x1, y1, x2, y2, vertices)          \
505     do {								\
506 	(vertices)[0] = (x1);						\
507 	(vertices)[2] = (x2);						\
508 	(vertices)[6] = (vertices)[2];					\
509 	(vertices)[4] = (vertices)[0];					\
510         (vertices)[1] = (y1);                                           \
511         (vertices)[7] = (y2);                                           \
512 	(vertices)[3] = (vertices)[1];					\
513 	(vertices)[5] = (vertices)[7];					\
514     } while(0)
515 
516 #define glamor_set_normalize_vcoords_ext(priv, xscale, yscale,		\
517 				     x1, y1, x2, y2,			\
518                                          vertices, stride)              \
519   do {									\
520     int fbo_x_off, fbo_y_off;						\
521     /* vertices may be write-only, so we use following			\
522      * temporary variable. */						\
523     float _t0_, _t1_, _t2_, _t5_;					\
524     pixmap_priv_get_fbo_off(priv, &fbo_x_off, &fbo_y_off);		\
525     (vertices)[0] = _t0_ = v_from_x_coord_x(xscale, x1 + fbo_x_off);	\
526     (vertices)[1 * stride] = _t2_ = v_from_x_coord_x(xscale,		\
527 					x2 + fbo_x_off);		\
528     (vertices)[2 * stride] = _t2_;					\
529     (vertices)[3 * stride] = _t0_;					\
530     (vertices)[1] = _t1_ = v_from_x_coord_y(yscale, y1 + fbo_y_off);    \
531     (vertices)[2 * stride + 1] = _t5_ =                                 \
532         v_from_x_coord_y(yscale, y2 + fbo_y_off);                       \
533     (vertices)[1 * stride + 1] = _t1_;					\
534     (vertices)[3 * stride + 1] = _t5_;					\
535   } while(0)
536 
537 #define glamor_set_normalize_vcoords_tri_strip(xscale, yscale,		\
538 					       x1, y1, x2, y2,		\
539 					       vertices)		\
540     do {								\
541 	(vertices)[0] = v_from_x_coord_x(xscale, x1);			\
542 	(vertices)[2] = v_from_x_coord_x(xscale, x2);			\
543 	(vertices)[6] = (vertices)[2];					\
544 	(vertices)[4] = (vertices)[0];					\
545         (vertices)[1] = v_from_x_coord_y(yscale, y1);                   \
546         (vertices)[7] = v_from_x_coord_y(yscale, y2);                   \
547 	(vertices)[3] = (vertices)[1];					\
548 	(vertices)[5] = (vertices)[7];					\
549     } while(0)
550 
551 #define glamor_set_normalize_pt(xscale, yscale, x, y,		\
552                                 pt)				\
553     do {							\
554         (pt)[0] = t_from_x_coord_x(xscale, x);			\
555         (pt)[1] = t_from_x_coord_y(yscale, y);                  \
556     } while(0)
557 
558 #define glamor_set_circle_centre(width, height, x, y,	\
559 				 c)		\
560     do {						\
561         (c)[0] = (float)x;				\
562         (c)[1] = (float)y;				\
563     } while(0)
564 
565 #define ALIGN(i,m)	(((i) + (m) - 1) & ~((m) - 1))
566 #define MIN(a,b)	((a) < (b) ? (a) : (b))
567 #define MAX(a,b)	((a) > (b) ? (a) : (b))
568 
569 #define glamor_check_fbo_size(_glamor_,_w_, _h_)    ((_w_) > 0 && (_h_) > 0 \
570                                                     && (_w_) <= _glamor_->max_fbo_size  \
571                                                     && (_h_) <= _glamor_->max_fbo_size)
572 
573 /* For 1bpp pixmap, we don't store it as texture. */
574 #define glamor_check_pixmap_fbo_depth(_depth_) (			\
575 						_depth_ == 8		\
576 						|| _depth_ == 15	\
577 						|| _depth_ == 16	\
578 						|| _depth_ == 24	\
579 						|| _depth_ == 30	\
580 						|| _depth_ == 32)
581 
582 #define GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)    (pixmap_priv->gl_fbo == GLAMOR_FBO_NORMAL)
583 
584 /**
585  * Borrow from uxa.
586  */
587 static inline CARD32
format_for_depth(int depth)588 format_for_depth(int depth)
589 {
590     switch (depth) {
591     case 1:
592         return PICT_a1;
593     case 4:
594         return PICT_a4;
595     case 8:
596         return PICT_a8;
597     case 15:
598         return PICT_x1r5g5b5;
599     case 16:
600         return PICT_r5g6b5;
601     default:
602     case 24:
603         return PICT_x8r8g8b8;
604     case 30:
605         return PICT_x2r10g10b10;
606     case 32:
607         return PICT_a8r8g8b8;
608     }
609 }
610 
611 static inline GLenum
gl_iformat_for_pixmap(PixmapPtr pixmap)612 gl_iformat_for_pixmap(PixmapPtr pixmap)
613 {
614     glamor_screen_private *glamor_priv =
615         glamor_get_screen_private((pixmap)->drawable.pScreen);
616 
617     if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP &&
618         ((pixmap)->drawable.depth == 1 || (pixmap)->drawable.depth == 8)) {
619         return glamor_priv->one_channel_format;
620     } else if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP &&
621                (pixmap)->drawable.depth == 30) {
622         return GL_RGB10_A2;
623     } else {
624         return GL_RGBA;
625     }
626 }
627 
628 static inline CARD32
format_for_pixmap(PixmapPtr pixmap)629 format_for_pixmap(PixmapPtr pixmap)
630 {
631     return format_for_depth((pixmap)->drawable.depth);
632 }
633 
634 #define REVERT_NONE       		0
635 #define REVERT_NORMAL     		1
636 #define REVERT_UPLOADING_A1		3
637 
638 #define SWAP_UPLOADING	  	2
639 #define SWAP_NONE_UPLOADING	3
640 
641 /* borrowed from uxa */
642 static inline Bool
glamor_get_rgba_from_pixel(CARD32 pixel,float * red,float * green,float * blue,float * alpha,CARD32 format)643 glamor_get_rgba_from_pixel(CARD32 pixel,
644                            float *red,
645                            float *green,
646                            float *blue, float *alpha, CARD32 format)
647 {
648     int rbits, bbits, gbits, abits;
649     int rshift, bshift, gshift, ashift;
650 
651     rbits = PICT_FORMAT_R(format);
652     gbits = PICT_FORMAT_G(format);
653     bbits = PICT_FORMAT_B(format);
654     abits = PICT_FORMAT_A(format);
655 
656     if (PICT_FORMAT_TYPE(format) == PICT_TYPE_A) {
657         rshift = gshift = bshift = ashift = 0;
658     }
659     else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
660         bshift = 0;
661         gshift = bbits;
662         rshift = gshift + gbits;
663         ashift = rshift + rbits;
664     }
665     else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) {
666         rshift = 0;
667         gshift = rbits;
668         bshift = gshift + gbits;
669         ashift = bshift + bbits;
670     }
671     else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) {
672         ashift = 0;
673         rshift = abits;
674         if (abits == 0)
675             rshift = PICT_FORMAT_BPP(format) - (rbits + gbits + bbits);
676         gshift = rshift + rbits;
677         bshift = gshift + gbits;
678     }
679     else {
680         return FALSE;
681     }
682 #define COLOR_INT_TO_FLOAT(_fc_, _p_, _s_, _bits_)	\
683   *_fc_ = (((_p_) >> (_s_)) & (( 1 << (_bits_)) - 1))	\
684     / (float)((1<<(_bits_)) - 1)
685 
686     if (rbits)
687         COLOR_INT_TO_FLOAT(red, pixel, rshift, rbits);
688     else
689         *red = 0;
690 
691     if (gbits)
692         COLOR_INT_TO_FLOAT(green, pixel, gshift, gbits);
693     else
694         *green = 0;
695 
696     if (bbits)
697         COLOR_INT_TO_FLOAT(blue, pixel, bshift, bbits);
698     else
699         *blue = 0;
700 
701     if (abits)
702         COLOR_INT_TO_FLOAT(alpha, pixel, ashift, abits);
703     else
704         *alpha = 1;
705 
706     return TRUE;
707 }
708 
709 static inline void
glamor_get_rgba_from_color(const xRenderColor * color,float rgba[4])710 glamor_get_rgba_from_color(const xRenderColor *color, float rgba[4])
711 {
712     rgba[0] = color->red   / (float)UINT16_MAX;
713     rgba[1] = color->green / (float)UINT16_MAX;
714     rgba[2] = color->blue  / (float)UINT16_MAX;
715     rgba[3] = color->alpha / (float)UINT16_MAX;
716 }
717 
718 inline static Bool
glamor_is_large_pixmap(PixmapPtr pixmap)719 glamor_is_large_pixmap(PixmapPtr pixmap)
720 {
721     glamor_pixmap_private *priv;
722 
723     priv = glamor_get_pixmap_private(pixmap);
724     return (glamor_pixmap_priv_is_large(priv));
725 }
726 
727 static inline void
glamor_make_current(glamor_screen_private * glamor_priv)728 glamor_make_current(glamor_screen_private *glamor_priv)
729 {
730     if (lastGLContext != glamor_priv->ctx.ctx) {
731         lastGLContext = glamor_priv->ctx.ctx;
732         glamor_priv->ctx.make_current(&glamor_priv->ctx);
733     }
734 }
735 
736 static inline BoxRec
glamor_no_rendering_bounds(void)737 glamor_no_rendering_bounds(void)
738 {
739     BoxRec bounds = {
740         .x1 = 0,
741         .y1 = 0,
742         .x2 = MAXSHORT,
743         .y2 = MAXSHORT,
744     };
745 
746     return bounds;
747 }
748 
749 static inline BoxRec
glamor_start_rendering_bounds(void)750 glamor_start_rendering_bounds(void)
751 {
752     BoxRec bounds = {
753         .x1 = MAXSHORT,
754         .y1 = MAXSHORT,
755         .x2 = 0,
756         .y2 = 0,
757     };
758 
759     return bounds;
760 }
761 
762 static inline void
glamor_bounds_union_rect(BoxPtr bounds,xRectangle * rect)763 glamor_bounds_union_rect(BoxPtr bounds, xRectangle *rect)
764 {
765     bounds->x1 = min(bounds->x1, rect->x);
766     bounds->y1 = min(bounds->y1, rect->y);
767     bounds->x2 = min(SHRT_MAX, max(bounds->x2, rect->x + rect->width));
768     bounds->y2 = min(SHRT_MAX, max(bounds->y2, rect->y + rect->height));
769 }
770 
771 static inline void
glamor_bounds_union_box(BoxPtr bounds,BoxPtr box)772 glamor_bounds_union_box(BoxPtr bounds, BoxPtr box)
773 {
774     bounds->x1 = min(bounds->x1, box->x1);
775     bounds->y1 = min(bounds->y1, box->y1);
776     bounds->x2 = max(bounds->x2, box->x2);
777     bounds->y2 = max(bounds->y2, box->y2);
778 }
779 
780 /**
781  * Helper function for implementing draws with GL_QUADS on GLES2,
782  * where we don't have them.
783  */
784 static inline void
glamor_glDrawArrays_GL_QUADS(glamor_screen_private * glamor_priv,unsigned count)785 glamor_glDrawArrays_GL_QUADS(glamor_screen_private *glamor_priv, unsigned count)
786 {
787     if (glamor_priv->use_quads) {
788         glDrawArrays(GL_QUADS, 0, count * 4);
789     } else {
790         glamor_gldrawarrays_quads_using_indices(glamor_priv, count);
791     }
792 }
793 
794 
795 #endif
796