1 #ifndef SNA_DAMAGE_H
2 #define SNA_DAMAGE_H
3 
4 #include <regionstr.h>
5 
6 #include "compiler.h"
7 
8 struct sna_damage {
9 	BoxRec extents;
10 	pixman_region16_t region;
11 	enum sna_damage_mode {
12 		DAMAGE_ADD = 0,
13 		DAMAGE_SUBTRACT,
14 		DAMAGE_ALL,
15 	} mode;
16 	int remain, dirty;
17 	BoxPtr box;
18 	struct {
19 		struct list list;
20 		int size;
21 		BoxRec box[8];
22 	} embedded_box;
23 };
24 
25 #define DAMAGE_IS_ALL(ptr) (((uintptr_t)(ptr))&1)
26 #define DAMAGE_MARK_ALL(ptr) ((struct sna_damage *)(((uintptr_t)(ptr))|1))
27 #define DAMAGE_PTR(ptr) ((struct sna_damage *)(((uintptr_t)(ptr))&~1))
28 #define DAMAGE_REGION(ptr) (&DAMAGE_PTR(ptr)->region)
29 
30 struct sna_damage *sna_damage_create(void);
31 
32 struct sna_damage *__sna_damage_all(struct sna_damage *damage,
33 				    int width, int height);
34 static inline struct sna_damage *
_sna_damage_all(struct sna_damage * damage,int width,int height)35 _sna_damage_all(struct sna_damage *damage,
36 		int width, int height)
37 {
38 	damage = __sna_damage_all(damage, width, height);
39 	return DAMAGE_MARK_ALL(damage);
40 }
41 
sna_damage_all(struct sna_damage ** damage,PixmapPtr pixmap)42 static inline void sna_damage_all(struct sna_damage **damage,
43 				  PixmapPtr pixmap)
44 {
45 	if (!DAMAGE_IS_ALL(*damage))
46 		*damage = _sna_damage_all(*damage,
47 					  pixmap->drawable.width,
48 					  pixmap->drawable.height);
49 }
50 
51 struct sna_damage *_sna_damage_combine(struct sna_damage *l,
52 				       struct sna_damage *r,
53 				       int dx, int dy);
sna_damage_combine(struct sna_damage ** l,struct sna_damage * r,int dx,int dy)54 static inline void sna_damage_combine(struct sna_damage **l,
55 				      struct sna_damage *r,
56 				      int dx, int dy)
57 {
58 	assert(!DAMAGE_IS_ALL(*l));
59 	*l = _sna_damage_combine(*l, DAMAGE_PTR(r), dx, dy);
60 }
61 
62 fastcall struct sna_damage *_sna_damage_add(struct sna_damage *damage,
63 					    RegionPtr region);
sna_damage_add(struct sna_damage ** damage,RegionPtr region)64 static inline void sna_damage_add(struct sna_damage **damage,
65 				  RegionPtr region)
66 {
67 	assert(!DAMAGE_IS_ALL(*damage));
68 	*damage = _sna_damage_add(*damage, region);
69 }
70 
sna_damage_add_to_pixmap(struct sna_damage ** damage,RegionPtr region,PixmapPtr pixmap)71 static inline bool sna_damage_add_to_pixmap(struct sna_damage **damage,
72 					    RegionPtr region,
73 					    PixmapPtr pixmap)
74 {
75 	assert(!DAMAGE_IS_ALL(*damage));
76 	if (region->data == NULL &&
77 	    region->extents.x2 - region->extents.x1 >= pixmap->drawable.width &&
78 	    region->extents.y2 - region->extents.y1 >= pixmap->drawable.height) {
79 		*damage = _sna_damage_all(*damage,
80 					  pixmap->drawable.width,
81 					  pixmap->drawable.height);
82 		return true;
83 	} else {
84 		*damage = _sna_damage_add(*damage, region);
85 		return false;
86 	}
87 }
88 
89 fastcall struct sna_damage *_sna_damage_add_box(struct sna_damage *damage,
90 						const BoxRec *box);
sna_damage_add_box(struct sna_damage ** damage,const BoxRec * box)91 static inline void sna_damage_add_box(struct sna_damage **damage,
92 				      const BoxRec *box)
93 {
94 	assert(!DAMAGE_IS_ALL(*damage));
95 	*damage = _sna_damage_add_box(*damage, box);
96 }
97 
98 struct sna_damage *_sna_damage_add_boxes(struct sna_damage *damage,
99 					 const BoxRec *box, int n,
100 					 int16_t dx, int16_t dy);
sna_damage_add_boxes(struct sna_damage ** damage,const BoxRec * box,int n,int16_t dx,int16_t dy)101 static inline void sna_damage_add_boxes(struct sna_damage **damage,
102 					const BoxRec *box, int n,
103 					int16_t dx, int16_t dy)
104 {
105 	assert(!DAMAGE_IS_ALL(*damage));
106 	*damage = _sna_damage_add_boxes(*damage, box, n, dx, dy);
107 }
108 
109 struct sna_damage *_sna_damage_add_rectangles(struct sna_damage *damage,
110 					      const xRectangle *r, int n,
111 					      int16_t dx, int16_t dy);
sna_damage_add_rectangles(struct sna_damage ** damage,const xRectangle * r,int n,int16_t dx,int16_t dy)112 static inline void sna_damage_add_rectangles(struct sna_damage **damage,
113 					     const xRectangle *r, int n,
114 					     int16_t dx, int16_t dy)
115 {
116 	if (damage) {
117 		assert(!DAMAGE_IS_ALL(*damage));
118 		*damage = _sna_damage_add_rectangles(*damage, r, n, dx, dy);
119 	}
120 }
121 
122 struct sna_damage *_sna_damage_add_points(struct sna_damage *damage,
123 					  const DDXPointRec *p, int n,
124 					  int16_t dx, int16_t dy);
sna_damage_add_points(struct sna_damage ** damage,const DDXPointRec * p,int n,int16_t dx,int16_t dy)125 static inline void sna_damage_add_points(struct sna_damage **damage,
126 					 const DDXPointRec *p, int n,
127 					 int16_t dx, int16_t dy)
128 {
129 	if (damage) {
130 		assert(!DAMAGE_IS_ALL(*damage));
131 		*damage = _sna_damage_add_points(*damage, p, n, dx, dy);
132 	}
133 }
134 
135 struct sna_damage *_sna_damage_is_all(struct sna_damage *damage,
136 				       int width, int height);
sna_damage_is_all(struct sna_damage ** _damage,int width,int height)137 static inline bool sna_damage_is_all(struct sna_damage **_damage,
138 				     int width, int height)
139 {
140 	struct sna_damage *damage = *_damage;
141 
142 	if (damage == NULL)
143 		return false;
144 	if (DAMAGE_IS_ALL(damage))
145 		return true;
146 
147 	switch (damage->mode) {
148 	case DAMAGE_ALL:
149 		assert(0);
150 		return true;
151 	case DAMAGE_SUBTRACT:
152 		return false;
153 	default:
154 		assert(0);
155 		/* fall through */
156 	case DAMAGE_ADD:
157 		if (damage->extents.x2 < width  || damage->extents.x1 > 0)
158 			return false;
159 		if (damage->extents.y2 < height || damage->extents.y1 > 0)
160 			return false;
161 		damage = _sna_damage_is_all(damage, width, height);
162 		if (damage->mode == DAMAGE_ALL) {
163 			*_damage = DAMAGE_MARK_ALL(damage);
164 			return true;
165 		} else {
166 			*_damage = damage;
167 			return false;
168 		}
169 	}
170 }
171 
172 fastcall struct sna_damage *_sna_damage_subtract(struct sna_damage *damage,
173 						 RegionPtr region);
sna_damage_subtract(struct sna_damage ** damage,RegionPtr region)174 static inline void sna_damage_subtract(struct sna_damage **damage,
175 				       RegionPtr region)
176 {
177 	*damage = _sna_damage_subtract(DAMAGE_PTR(*damage), region);
178 	assert(*damage == NULL || (*damage)->mode != DAMAGE_ALL);
179 }
180 
181 fastcall struct sna_damage *_sna_damage_subtract_box(struct sna_damage *damage,
182 						     const BoxRec *box);
sna_damage_subtract_box(struct sna_damage ** damage,const BoxRec * box)183 static inline void sna_damage_subtract_box(struct sna_damage **damage,
184 					   const BoxRec *box)
185 {
186 	*damage = _sna_damage_subtract_box(DAMAGE_PTR(*damage), box);
187 	assert(*damage == NULL || (*damage)->mode != DAMAGE_ALL);
188 }
189 
190 fastcall struct sna_damage *_sna_damage_subtract_boxes(struct sna_damage *damage,
191 						       const BoxRec *box, int n,
192 						       int dx, int dy);
sna_damage_subtract_boxes(struct sna_damage ** damage,const BoxRec * box,int n,int dx,int dy)193 static inline void sna_damage_subtract_boxes(struct sna_damage **damage,
194 					     const BoxRec *box, int n,
195 					     int dx, int dy)
196 {
197 	*damage = _sna_damage_subtract_boxes(DAMAGE_PTR(*damage),
198 					     box, n, dx, dy);
199 	assert(*damage == NULL || (*damage)->mode != DAMAGE_ALL);
200 }
201 
202 bool _sna_damage_intersect(struct sna_damage *damage,
203 			  RegionPtr region, RegionPtr result);
204 
sna_damage_intersect(struct sna_damage * damage,RegionPtr region,RegionPtr result)205 static inline bool sna_damage_intersect(struct sna_damage *damage,
206 					RegionPtr region, RegionPtr result)
207 {
208 	assert(damage);
209 	assert(RegionNotEmpty(region));
210 	assert(!DAMAGE_IS_ALL(damage));
211 
212 	return _sna_damage_intersect(damage, region, result);
213 }
214 
215 static inline bool
sna_damage_overlaps_box(const struct sna_damage * damage,const BoxRec * box)216 sna_damage_overlaps_box(const struct sna_damage *damage,
217 			const BoxRec *box)
218 {
219 	if (box->x2 <= damage->extents.x1 ||
220 	    box->x1 >= damage->extents.x2)
221 		return false;
222 
223 	if (box->y2 <= damage->extents.y1 ||
224 	    box->y1 >= damage->extents.y2)
225 		return false;
226 
227 	return true;
228 }
229 
230 int _sna_damage_contains_box(struct sna_damage **damage,
231 			     const BoxRec *box);
sna_damage_contains_box(struct sna_damage ** damage,const BoxRec * box)232 static inline int sna_damage_contains_box(struct sna_damage **damage,
233 					  const BoxRec *box)
234 {
235 	if (DAMAGE_IS_ALL(*damage))
236 		return PIXMAN_REGION_IN;
237 	if (*damage == NULL)
238 		return PIXMAN_REGION_OUT;
239 
240 	return _sna_damage_contains_box(damage, box);
241 }
sna_damage_contains_box__offset(struct sna_damage ** damage,const BoxRec * box,int dx,int dy)242 static inline int sna_damage_contains_box__offset(struct sna_damage **damage,
243 						  const BoxRec *box, int dx, int dy)
244 {
245 	BoxRec b;
246 
247 	if (DAMAGE_IS_ALL(*damage))
248 		return PIXMAN_REGION_IN;
249 	if (*damage == NULL)
250 		return PIXMAN_REGION_OUT;
251 
252 	b = *box;
253 	b.x1 += dx; b.x2 += dx;
254 	b.y1 += dy; b.y2 += dy;
255 	return _sna_damage_contains_box(damage, &b);
256 }
257 bool _sna_damage_contains_box__no_reduce(const struct sna_damage *damage,
258 					const BoxRec *box);
259 static inline bool
sna_damage_contains_box__no_reduce(const struct sna_damage * damage,const BoxRec * box)260 sna_damage_contains_box__no_reduce(const struct sna_damage *damage,
261 				   const BoxRec *box)
262 {
263 	assert(!DAMAGE_IS_ALL(damage));
264 	return _sna_damage_contains_box__no_reduce(damage, box);
265 }
266 
267 int _sna_damage_get_boxes(struct sna_damage *damage, const BoxRec **boxes);
268 static inline int
sna_damage_get_boxes(struct sna_damage * damage,const BoxRec ** boxes)269 sna_damage_get_boxes(struct sna_damage *damage, const BoxRec **boxes)
270 {
271 	assert(DAMAGE_PTR(damage));
272 
273 	if (DAMAGE_IS_ALL(damage)) {
274 		*boxes = &DAMAGE_PTR(damage)->extents;
275 		return 1;
276 	} else
277 		return _sna_damage_get_boxes(damage, boxes);
278 }
279 
280 struct sna_damage *_sna_damage_reduce(struct sna_damage *damage);
sna_damage_reduce(struct sna_damage ** damage)281 static inline void sna_damage_reduce(struct sna_damage **damage)
282 {
283 	if (*damage == NULL)
284 		return;
285 
286 	if (!DAMAGE_IS_ALL(*damage) && (*damage)->dirty)
287 		*damage = _sna_damage_reduce(*damage);
288 }
289 
sna_damage_reduce_all(struct sna_damage ** _damage,PixmapPtr pixmap)290 static inline void sna_damage_reduce_all(struct sna_damage **_damage,
291 					 PixmapPtr pixmap)
292 {
293 	struct sna_damage *damage = *_damage;
294 
295 	if (damage == NULL || DAMAGE_IS_ALL(damage))
296 		return;
297 
298 	DBG(("%s(width=%d, height=%d)\n", __FUNCTION__, pixmap->drawable.width, pixmap->drawable.height));
299 
300 	if (damage->mode == DAMAGE_ADD) {
301 		if (damage->extents.x1 <= 0 &&
302 		    damage->extents.y1 <= 0 &&
303 		    damage->extents.x2 >= pixmap->drawable.width &&
304 		    damage->extents.y2 >= pixmap->drawable.height) {
305 			if (damage->dirty) {
306 				damage = *_damage = _sna_damage_reduce(damage);
307 				if (damage == NULL)
308 					return;
309 			}
310 
311 			if (damage->region.data == NULL)
312 				*_damage = _sna_damage_all(damage,
313 							   pixmap->drawable.width,
314 							   pixmap->drawable.height);
315 		}
316 	} else
317 		*_damage = _sna_damage_reduce(damage);
318 }
319 
320 void __sna_damage_destroy(struct sna_damage *damage);
sna_damage_destroy(struct sna_damage ** damage)321 static inline void sna_damage_destroy(struct sna_damage **damage)
322 {
323 	if (*damage == NULL)
324 		return;
325 
326 	if (DAMAGE_PTR(*damage))
327 		__sna_damage_destroy(DAMAGE_PTR(*damage));
328 	*damage = NULL;
329 }
330 
331 void _sna_damage_debug_get_region(struct sna_damage *damage, RegionRec *r);
332 
333 #if HAS_DEBUG_FULL && TEST_DAMAGE
334 void sna_damage_selftest(void);
335 #else
sna_damage_selftest(void)336 static inline void sna_damage_selftest(void) {}
337 #endif
338 
339 #endif /* SNA_DAMAGE_H */
340