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