1#ifndef SNA_RENDER_INLINE_H 2#define SNA_RENDER_INLINE_H 3 4static inline bool need_tiling(struct sna *sna, int16_t width, int16_t height) 5{ 6 /* Is the damage area too large to fit in 3D pipeline, 7 * and so do we need to split the operation up into tiles? 8 */ 9 return (width > sna->render.max_3d_size || 10 height > sna->render.max_3d_size); 11} 12 13static inline bool need_redirect(struct sna *sna, PixmapPtr dst) 14{ 15 /* Is the pixmap too large to render to? */ 16 return (dst->drawable.width > sna->render.max_3d_size || 17 dst->drawable.height > sna->render.max_3d_size); 18} 19 20static force_inline float pack_2s(int16_t x, int16_t y) 21{ 22 union { 23 struct sna_coordinate p; 24 float f; 25 } u; 26 u.p.x = x; 27 u.p.y = y; 28 return u.f; 29} 30 31static force_inline int vertex_space(struct sna *sna) 32{ 33 return sna->render.vertex_size - sna->render.vertex_used; 34} 35static force_inline void vertex_emit(struct sna *sna, float v) 36{ 37 assert(sna->render.vertex_used < sna->render.vertex_size); 38 sna->render.vertices[sna->render.vertex_used++] = v; 39} 40static force_inline void vertex_emit_2s(struct sna *sna, int16_t x, int16_t y) 41{ 42 vertex_emit(sna, pack_2s(x, y)); 43} 44 45static force_inline int batch_space(struct sna *sna) 46{ 47 assert(sna->kgem.nbatch <= KGEM_BATCH_SIZE(&sna->kgem)); 48 assert(sna->kgem.nbatch + KGEM_BATCH_RESERVED <= sna->kgem.surface); 49 return sna->kgem.surface - sna->kgem.nbatch - KGEM_BATCH_RESERVED; 50} 51 52static force_inline void batch_emit(struct sna *sna, uint32_t dword) 53{ 54 assert(sna->kgem.mode != KGEM_NONE); 55 assert(sna->kgem.nbatch + KGEM_BATCH_RESERVED < sna->kgem.surface); 56 sna->kgem.batch[sna->kgem.nbatch++] = dword; 57} 58 59static force_inline void batch_emit_aligned(struct sna *sna, uint32_t dword, unsigned align) 60{ 61 assert(sna->kgem.mode != KGEM_NONE); 62 assert(sna->kgem.nbatch + KGEM_BATCH_RESERVED < sna->kgem.surface); 63 while (sna->kgem.nbatch & (align-1)) 64 sna->kgem.batch[sna->kgem.nbatch++] = 0; 65 sna->kgem.batch[sna->kgem.nbatch++] = dword; 66} 67 68static force_inline void batch_emit64(struct sna *sna, uint64_t qword) 69{ 70 assert(sna->kgem.mode != KGEM_NONE); 71 assert(sna->kgem.nbatch + 2 + KGEM_BATCH_RESERVED < sna->kgem.surface); 72 *(uint64_t *)(sna->kgem.batch+sna->kgem.nbatch) = qword; 73 sna->kgem.nbatch += 2; 74} 75 76static force_inline void batch_emit_float(struct sna *sna, float f) 77{ 78 union { 79 uint32_t dw; 80 float f; 81 } u; 82 u.f = f; 83 batch_emit(sna, u.dw); 84} 85 86static inline bool 87is_gpu(struct sna *sna, DrawablePtr drawable, unsigned prefer) 88{ 89 struct sna_pixmap *priv = sna_pixmap_from_drawable(drawable); 90 91 if (priv == NULL || priv->clear || priv->cpu) 92 return false; 93 94 if (priv->cpu_damage == NULL) 95 return true; 96 97 if (priv->gpu_damage && !priv->gpu_bo->proxy && 98 (sna->render.prefer_gpu & prefer)) 99 return true; 100 101 if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) 102 return true; 103 104 if (DAMAGE_IS_ALL(priv->cpu_damage)) 105 return false; 106 107 return priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo); 108} 109 110static inline bool 111too_small(struct sna_pixmap *priv) 112{ 113 assert(priv); 114 115 if (priv->gpu_bo) 116 return false; 117 118 if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) 119 return false; 120 121 return (priv->create & KGEM_CAN_CREATE_GPU) == 0; 122} 123 124static inline bool 125can_render_to_picture(PicturePtr dst) 126{ 127 if (dst->alphaMap) { 128 DBG(("%s(pixmap=%ld) -- no, has alphamap\n", __FUNCTION__, 129 get_drawable_pixmap(dst->pDrawable)->drawable.serialNumber)); 130 return false; 131 } 132 133 switch (PICT_FORMAT_TYPE(dst->format)) { 134 case PICT_TYPE_COLOR: 135 case PICT_TYPE_GRAY: 136 case PICT_TYPE_OTHER: 137 DBG(("%s(pixmap=%ld) -- no, has palette\n", __FUNCTION__, 138 get_drawable_pixmap(dst->pDrawable)->drawable.serialNumber)); 139 return false; 140 default: 141 break; 142 } 143 144 return true; 145} 146 147 148static inline bool 149is_gpu_dst(struct sna_pixmap *priv) 150{ 151 assert(priv); 152 153 if (too_small(priv)) 154 return false; 155 156 if (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo)) 157 return true; 158 159 if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) 160 return true; 161 162 if (DAMAGE_IS_ALL(priv->cpu_damage)) 163 return false; 164 165 return priv->gpu_damage != NULL || !priv->cpu; 166} 167 168static inline bool 169unattached(DrawablePtr drawable) 170{ 171 struct sna_pixmap *priv = sna_pixmap_from_drawable(drawable); 172 return priv == NULL || (priv->gpu_damage == NULL && priv->cpu_damage && !priv->cpu_bo); 173} 174 175static inline bool 176picture_is_gpu(struct sna *sna, PicturePtr picture, unsigned flags) 177{ 178 if (!picture) 179 return false; 180 181 if (!picture->pDrawable) { 182 switch (flags) { 183 case PREFER_GPU_RENDER: 184 switch (picture->pSourcePict->type) { 185 case SourcePictTypeSolidFill: 186 case SourcePictTypeLinear: 187 return false; 188 default: 189 return true; 190 } 191 case PREFER_GPU_SPANS: 192 return true; 193 default: 194 return false; 195 } 196 } else { 197 if (picture->repeat && 198 (picture->pDrawable->width | picture->pDrawable->height) == 1) 199 return flags == PREFER_GPU_SPANS; 200 } 201 202 return is_gpu(sna, picture->pDrawable, flags); 203} 204 205static inline bool 206picture_is_cpu(struct sna *sna, PicturePtr picture) 207{ 208 if (!picture->pDrawable) 209 return false; 210 211 return !is_gpu(sna, picture->pDrawable, PREFER_GPU_RENDER); 212} 213 214static inline bool sna_blt_compare_depth(const DrawableRec *src, const DrawableRec *dst) 215{ 216 if (src->depth == dst->depth) 217 return true; 218 219 /* Also allow for the alpha to be discarded on a copy */ 220 if (src->bitsPerPixel != dst->bitsPerPixel) 221 return false; 222 223 if (dst->depth == 24 && src->depth == 32) 224 return true; 225 226 /* Note that a depth-16 pixmap is r5g6b5, not x1r5g5b5. */ 227 228 return false; 229} 230 231static inline struct kgem_bo * 232sna_render_get_alpha_gradient(struct sna *sna) 233{ 234 return kgem_bo_reference(sna->render.alpha_cache.cache_bo); 235} 236 237static inline void 238sna_render_picture_extents(PicturePtr p, BoxRec *box) 239{ 240 box->x1 = p->pDrawable->x; 241 box->y1 = p->pDrawable->y; 242 box->x2 = bound(box->x1, p->pDrawable->width); 243 box->y2 = bound(box->y1, p->pDrawable->height); 244 245 if (box->x1 < p->pCompositeClip->extents.x1) 246 box->x1 = p->pCompositeClip->extents.x1; 247 if (box->y1 < p->pCompositeClip->extents.y1) 248 box->y1 = p->pCompositeClip->extents.y1; 249 250 if (box->x2 > p->pCompositeClip->extents.x2) 251 box->x2 = p->pCompositeClip->extents.x2; 252 if (box->y2 > p->pCompositeClip->extents.y2) 253 box->y2 = p->pCompositeClip->extents.y2; 254 255 assert(box->x2 > box->x1 && box->y2 > box->y1); 256} 257 258static inline void 259sna_render_reduce_damage(struct sna_composite_op *op, 260 int dst_x, int dst_y, 261 int width, int height) 262{ 263 BoxRec r; 264 265 if (op->damage == NULL || *op->damage == NULL) 266 return; 267 268 if (DAMAGE_IS_ALL(*op->damage)) { 269 DBG(("%s: damage-all, dicarding damage\n", 270 __FUNCTION__)); 271 op->damage = NULL; 272 return; 273 } 274 275 if (width == 0 || height == 0) 276 return; 277 278 r.x1 = dst_x + op->dst.x; 279 r.x2 = r.x1 + width; 280 281 r.y1 = dst_y + op->dst.y; 282 r.y2 = r.y1 + height; 283 284 if (sna_damage_contains_box__no_reduce(*op->damage, &r)) { 285 DBG(("%s: damage contains render extents, dicarding damage\n", 286 __FUNCTION__)); 287 op->damage = NULL; 288 } 289} 290 291inline static uint32_t 292color_convert(uint32_t pixel, 293 uint32_t src_format, 294 uint32_t dst_format) 295{ 296 DBG(("%s: src=%08x [%08x]\n", __FUNCTION__, pixel, src_format)); 297 298 if (src_format != dst_format) { 299 uint16_t red, green, blue, alpha; 300 301 if (!sna_get_rgba_from_pixel(pixel, 302 &red, &green, &blue, &alpha, 303 src_format)) 304 return 0; 305 306 if (!sna_get_pixel_from_rgba(&pixel, 307 red, green, blue, alpha, 308 dst_format)) 309 return 0; 310 } 311 312 DBG(("%s: dst=%08x [%08x]\n", __FUNCTION__, pixel, dst_format)); 313 return pixel; 314} 315 316inline static uint32_t 317solid_color(uint32_t format, uint32_t pixel) 318{ 319 return color_convert(pixel, format, PICT_a8r8g8b8); 320} 321 322inline static bool dst_use_gpu(PixmapPtr pixmap) 323{ 324 struct sna_pixmap *priv = sna_pixmap(pixmap); 325 if (priv == NULL) 326 return false; 327 328 if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) 329 return true; 330 331 if (priv->clear) 332 return false; 333 334 if (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo)) 335 return true; 336 337 return priv->gpu_damage && (!priv->cpu || !priv->cpu_damage); 338} 339 340inline static bool dst_use_cpu(PixmapPtr pixmap) 341{ 342 struct sna_pixmap *priv = sna_pixmap(pixmap); 343 if (priv == NULL || priv->shm) 344 return true; 345 346 return priv->cpu_damage && priv->cpu; 347} 348 349inline static bool dst_is_cpu(PixmapPtr pixmap) 350{ 351 struct sna_pixmap *priv = sna_pixmap(pixmap); 352 return priv == NULL || DAMAGE_IS_ALL(priv->cpu_damage); 353} 354 355inline static bool 356untransformed(PicturePtr p) 357{ 358 return !p->transform || pixman_transform_is_int_translate(p->transform); 359} 360 361inline static void 362boxes_extents(const BoxRec *box, int n, BoxRec *extents) 363{ 364 *extents = box[0]; 365 while (--n) { 366 box++; 367 368 if (box->x1 < extents->x1) 369 extents->x1 = box->x1; 370 if (box->x2 > extents->x2) 371 extents->x2 = box->x2; 372 373 if (box->y1 < extents->y1) 374 extents->y1 = box->y1; 375 if (box->y2 > extents->y2) 376 extents->y2 = box->y2; 377 } 378} 379 380inline static bool 381overlaps(struct sna *sna, 382 struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy, 383 struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy, 384 const BoxRec *box, int n, unsigned flags, 385 BoxRec *extents) 386{ 387 if (src_bo != dst_bo) 388 return false; 389 390 if (flags & COPY_NO_OVERLAP) 391 return false; 392 393 boxes_extents(box, n, extents); 394 return (extents->x2 + src_dx > extents->x1 + dst_dx && 395 extents->x1 + src_dx < extents->x2 + dst_dx && 396 extents->y2 + src_dy > extents->y1 + dst_dy && 397 extents->y1 + src_dy < extents->y2 + dst_dy); 398} 399 400static inline long get_picture_id(PicturePtr picture) 401{ 402 return picture && picture->pDrawable ? get_drawable_pixmap(picture->pDrawable)->drawable.serialNumber : 0; 403} 404 405#endif /* SNA_RENDER_INLINE_H */ 406