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_all(struct sna_damage *damage, 33 int width, int height); 34static inline struct sna_damage * 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 42static 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 51struct sna_damage *_sna_damage_combine(struct sna_damage *l, 52 struct sna_damage *r, 53 int dx, int dy); 54static 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 62fastcall struct sna_damage *_sna_damage_add(struct sna_damage *damage, 63 RegionPtr region); 64static 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 71static 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 89fastcall struct sna_damage *_sna_damage_add_box(struct sna_damage *damage, 90 const BoxRec *box); 91static 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 98struct sna_damage *_sna_damage_add_boxes(struct sna_damage *damage, 99 const BoxRec *box, int n, 100 int16_t dx, int16_t dy); 101static 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 109struct sna_damage *_sna_damage_add_rectangles(struct sna_damage *damage, 110 const xRectangle *r, int n, 111 int16_t dx, int16_t dy); 112static 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 122struct sna_damage *_sna_damage_add_points(struct sna_damage *damage, 123 const DDXPointRec *p, int n, 124 int16_t dx, int16_t dy); 125static 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 135struct sna_damage *_sna_damage_is_all(struct sna_damage *damage, 136 int width, int height); 137static 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 case DAMAGE_ADD: 156 if (damage->extents.x2 < width || damage->extents.x1 > 0) 157 return false; 158 if (damage->extents.y2 < height || damage->extents.y1 > 0) 159 return false; 160 damage = _sna_damage_is_all(damage, width, height); 161 if (damage->mode == DAMAGE_ALL) { 162 *_damage = DAMAGE_MARK_ALL(damage); 163 return true; 164 } else { 165 *_damage = damage; 166 return false; 167 } 168 } 169} 170 171fastcall struct sna_damage *_sna_damage_subtract(struct sna_damage *damage, 172 RegionPtr region); 173static inline void sna_damage_subtract(struct sna_damage **damage, 174 RegionPtr region) 175{ 176 *damage = _sna_damage_subtract(DAMAGE_PTR(*damage), region); 177 assert(*damage == NULL || (*damage)->mode != DAMAGE_ALL); 178} 179 180fastcall struct sna_damage *_sna_damage_subtract_box(struct sna_damage *damage, 181 const BoxRec *box); 182static inline void sna_damage_subtract_box(struct sna_damage **damage, 183 const BoxRec *box) 184{ 185 *damage = _sna_damage_subtract_box(DAMAGE_PTR(*damage), box); 186 assert(*damage == NULL || (*damage)->mode != DAMAGE_ALL); 187} 188 189fastcall struct sna_damage *_sna_damage_subtract_boxes(struct sna_damage *damage, 190 const BoxRec *box, int n, 191 int dx, int dy); 192static inline void sna_damage_subtract_boxes(struct sna_damage **damage, 193 const BoxRec *box, int n, 194 int dx, int dy) 195{ 196 *damage = _sna_damage_subtract_boxes(DAMAGE_PTR(*damage), 197 box, n, dx, dy); 198 assert(*damage == NULL || (*damage)->mode != DAMAGE_ALL); 199} 200 201bool _sna_damage_intersect(struct sna_damage *damage, 202 RegionPtr region, RegionPtr result); 203 204static inline bool sna_damage_intersect(struct sna_damage *damage, 205 RegionPtr region, RegionPtr result) 206{ 207 assert(damage); 208 assert(RegionNotEmpty(region)); 209 assert(!DAMAGE_IS_ALL(damage)); 210 211 return _sna_damage_intersect(damage, region, result); 212} 213 214static inline bool 215sna_damage_overlaps_box(const struct sna_damage *damage, 216 const BoxRec *box) 217{ 218 if (box->x2 <= damage->extents.x1 || 219 box->x1 >= damage->extents.x2) 220 return false; 221 222 if (box->y2 <= damage->extents.y1 || 223 box->y1 >= damage->extents.y2) 224 return false; 225 226 return true; 227} 228 229int _sna_damage_contains_box(struct sna_damage **damage, 230 const BoxRec *box); 231static inline int sna_damage_contains_box(struct sna_damage **damage, 232 const BoxRec *box) 233{ 234 if (DAMAGE_IS_ALL(*damage)) 235 return PIXMAN_REGION_IN; 236 if (*damage == NULL) 237 return PIXMAN_REGION_OUT; 238 239 return _sna_damage_contains_box(damage, box); 240} 241static inline int sna_damage_contains_box__offset(struct sna_damage **damage, 242 const BoxRec *box, int dx, int dy) 243{ 244 BoxRec b; 245 246 if (DAMAGE_IS_ALL(*damage)) 247 return PIXMAN_REGION_IN; 248 if (*damage == NULL) 249 return PIXMAN_REGION_OUT; 250 251 b = *box; 252 b.x1 += dx; b.x2 += dx; 253 b.y1 += dy; b.y2 += dy; 254 return _sna_damage_contains_box(damage, &b); 255} 256bool _sna_damage_contains_box__no_reduce(const struct sna_damage *damage, 257 const BoxRec *box); 258static inline bool 259sna_damage_contains_box__no_reduce(const struct sna_damage *damage, 260 const BoxRec *box) 261{ 262 assert(!DAMAGE_IS_ALL(damage)); 263 return _sna_damage_contains_box__no_reduce(damage, box); 264} 265 266int _sna_damage_get_boxes(struct sna_damage *damage, const BoxRec **boxes); 267static inline int 268sna_damage_get_boxes(struct sna_damage *damage, const BoxRec **boxes) 269{ 270 assert(DAMAGE_PTR(damage)); 271 272 if (DAMAGE_IS_ALL(damage)) { 273 *boxes = &DAMAGE_PTR(damage)->extents; 274 return 1; 275 } else 276 return _sna_damage_get_boxes(damage, boxes); 277} 278 279struct sna_damage *_sna_damage_reduce(struct sna_damage *damage); 280static inline void sna_damage_reduce(struct sna_damage **damage) 281{ 282 if (*damage == NULL) 283 return; 284 285 if (!DAMAGE_IS_ALL(*damage) && (*damage)->dirty) 286 *damage = _sna_damage_reduce(*damage); 287} 288 289static inline void sna_damage_reduce_all(struct sna_damage **_damage, 290 PixmapPtr pixmap) 291{ 292 struct sna_damage *damage = *_damage; 293 294 if (damage == NULL || DAMAGE_IS_ALL(damage)) 295 return; 296 297 DBG(("%s(width=%d, height=%d)\n", __FUNCTION__, pixmap->drawable.width, pixmap->drawable.height)); 298 299 if (damage->mode == DAMAGE_ADD) { 300 if (damage->extents.x1 <= 0 && 301 damage->extents.y1 <= 0 && 302 damage->extents.x2 >= pixmap->drawable.width && 303 damage->extents.y2 >= pixmap->drawable.height) { 304 if (damage->dirty) { 305 damage = *_damage = _sna_damage_reduce(damage); 306 if (damage == NULL) 307 return; 308 } 309 310 if (damage->region.data == NULL) 311 *_damage = _sna_damage_all(damage, 312 pixmap->drawable.width, 313 pixmap->drawable.height); 314 } 315 } else 316 *_damage = _sna_damage_reduce(damage); 317} 318 319void __sna_damage_destroy(struct sna_damage *damage); 320static inline void sna_damage_destroy(struct sna_damage **damage) 321{ 322 if (*damage == NULL) 323 return; 324 325 if (DAMAGE_PTR(*damage)) 326 __sna_damage_destroy(DAMAGE_PTR(*damage)); 327 *damage = NULL; 328} 329 330void _sna_damage_debug_get_region(struct sna_damage *damage, RegionRec *r); 331 332#if HAS_DEBUG_FULL && TEST_DAMAGE 333void sna_damage_selftest(void); 334#else 335static inline void sna_damage_selftest(void) {} 336#endif 337 338#endif /* SNA_DAMAGE_H */ 339