1428d7b3dSmrg#ifndef SNA_RENDER_INLINE_H
2428d7b3dSmrg#define SNA_RENDER_INLINE_H
3428d7b3dSmrg
4428d7b3dSmrgstatic inline bool need_tiling(struct sna *sna, int16_t width, int16_t height)
5428d7b3dSmrg{
6428d7b3dSmrg	/* Is the damage area too large to fit in 3D pipeline,
7428d7b3dSmrg	 * and so do we need to split the operation up into tiles?
8428d7b3dSmrg	 */
9428d7b3dSmrg	return (width > sna->render.max_3d_size ||
10428d7b3dSmrg		height > sna->render.max_3d_size);
11428d7b3dSmrg}
12428d7b3dSmrg
13428d7b3dSmrgstatic inline bool need_redirect(struct sna *sna, PixmapPtr dst)
14428d7b3dSmrg{
15428d7b3dSmrg	/* Is the pixmap too large to render to? */
16428d7b3dSmrg	return (dst->drawable.width > sna->render.max_3d_size ||
17428d7b3dSmrg		dst->drawable.height > sna->render.max_3d_size);
18428d7b3dSmrg}
19428d7b3dSmrg
20428d7b3dSmrgstatic force_inline float pack_2s(int16_t x, int16_t y)
21428d7b3dSmrg{
22428d7b3dSmrg	union {
23428d7b3dSmrg		struct sna_coordinate p;
24428d7b3dSmrg		float f;
25428d7b3dSmrg	} u;
26428d7b3dSmrg	u.p.x = x;
27428d7b3dSmrg	u.p.y = y;
28428d7b3dSmrg	return u.f;
29428d7b3dSmrg}
30428d7b3dSmrg
31428d7b3dSmrgstatic force_inline int vertex_space(struct sna *sna)
32428d7b3dSmrg{
33428d7b3dSmrg	return sna->render.vertex_size - sna->render.vertex_used;
34428d7b3dSmrg}
35428d7b3dSmrgstatic force_inline void vertex_emit(struct sna *sna, float v)
36428d7b3dSmrg{
37428d7b3dSmrg	assert(sna->render.vertex_used < sna->render.vertex_size);
38428d7b3dSmrg	sna->render.vertices[sna->render.vertex_used++] = v;
39428d7b3dSmrg}
40428d7b3dSmrgstatic force_inline void vertex_emit_2s(struct sna *sna, int16_t x, int16_t y)
41428d7b3dSmrg{
42428d7b3dSmrg	vertex_emit(sna, pack_2s(x, y));
43428d7b3dSmrg}
44428d7b3dSmrg
45428d7b3dSmrgstatic force_inline int batch_space(struct sna *sna)
46428d7b3dSmrg{
47428d7b3dSmrg	assert(sna->kgem.nbatch <= KGEM_BATCH_SIZE(&sna->kgem));
48428d7b3dSmrg	assert(sna->kgem.nbatch + KGEM_BATCH_RESERVED <= sna->kgem.surface);
49428d7b3dSmrg	return sna->kgem.surface - sna->kgem.nbatch - KGEM_BATCH_RESERVED;
50428d7b3dSmrg}
51428d7b3dSmrg
52428d7b3dSmrgstatic force_inline void batch_emit(struct sna *sna, uint32_t dword)
53428d7b3dSmrg{
54428d7b3dSmrg	assert(sna->kgem.mode != KGEM_NONE);
55428d7b3dSmrg	assert(sna->kgem.nbatch + KGEM_BATCH_RESERVED < sna->kgem.surface);
56428d7b3dSmrg	sna->kgem.batch[sna->kgem.nbatch++] = dword;
57428d7b3dSmrg}
58428d7b3dSmrg
59428d7b3dSmrgstatic force_inline void batch_emit64(struct sna *sna, uint64_t qword)
60428d7b3dSmrg{
61428d7b3dSmrg	assert(sna->kgem.mode != KGEM_NONE);
62428d7b3dSmrg	assert(sna->kgem.nbatch + 2 + KGEM_BATCH_RESERVED < sna->kgem.surface);
63428d7b3dSmrg	*(uint64_t *)(sna->kgem.batch+sna->kgem.nbatch) = qword;
64428d7b3dSmrg	sna->kgem.nbatch += 2;
65428d7b3dSmrg}
66428d7b3dSmrg
67428d7b3dSmrgstatic force_inline void batch_emit_float(struct sna *sna, float f)
68428d7b3dSmrg{
69428d7b3dSmrg	union {
70428d7b3dSmrg		uint32_t dw;
71428d7b3dSmrg		float f;
72428d7b3dSmrg	} u;
73428d7b3dSmrg	u.f = f;
74428d7b3dSmrg	batch_emit(sna, u.dw);
75428d7b3dSmrg}
76428d7b3dSmrg
77428d7b3dSmrgstatic inline bool
78428d7b3dSmrgis_gpu(struct sna *sna, DrawablePtr drawable, unsigned prefer)
79428d7b3dSmrg{
80428d7b3dSmrg	struct sna_pixmap *priv = sna_pixmap_from_drawable(drawable);
81428d7b3dSmrg
82428d7b3dSmrg	if (priv == NULL || priv->clear || priv->cpu)
83428d7b3dSmrg		return false;
84428d7b3dSmrg
85428d7b3dSmrg	if (priv->cpu_damage == NULL)
86428d7b3dSmrg		return true;
87428d7b3dSmrg
88428d7b3dSmrg	if (priv->gpu_damage && !priv->gpu_bo->proxy &&
89428d7b3dSmrg	    (sna->render.prefer_gpu & prefer))
90428d7b3dSmrg		return true;
91428d7b3dSmrg
92428d7b3dSmrg	if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo))
93428d7b3dSmrg		return true;
94428d7b3dSmrg
95428d7b3dSmrg	if (DAMAGE_IS_ALL(priv->cpu_damage))
96428d7b3dSmrg		return false;
97428d7b3dSmrg
98428d7b3dSmrg	return priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo);
99428d7b3dSmrg}
100428d7b3dSmrg
101428d7b3dSmrgstatic inline bool
102428d7b3dSmrgtoo_small(struct sna_pixmap *priv)
103428d7b3dSmrg{
104428d7b3dSmrg	assert(priv);
105428d7b3dSmrg
106428d7b3dSmrg	if (priv->gpu_bo)
107428d7b3dSmrg		return false;
108428d7b3dSmrg
109428d7b3dSmrg	if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo))
110428d7b3dSmrg		return false;
111428d7b3dSmrg
112428d7b3dSmrg	return (priv->create & KGEM_CAN_CREATE_GPU) == 0;
113428d7b3dSmrg}
114428d7b3dSmrg
115428d7b3dSmrgstatic inline bool
116428d7b3dSmrgcan_render_to_picture(PicturePtr dst)
117428d7b3dSmrg{
118428d7b3dSmrg	if (dst->alphaMap) {
119428d7b3dSmrg		DBG(("%s(pixmap=%ld) -- no, has alphamap\n", __FUNCTION__,
120428d7b3dSmrg		     get_drawable_pixmap(dst->pDrawable)->drawable.serialNumber));
121428d7b3dSmrg		return false;
122428d7b3dSmrg	}
123428d7b3dSmrg
124428d7b3dSmrg	switch (PICT_FORMAT_TYPE(dst->format)) {
125428d7b3dSmrg	case PICT_TYPE_COLOR:
126428d7b3dSmrg	case PICT_TYPE_GRAY:
127428d7b3dSmrg	case PICT_TYPE_OTHER:
128428d7b3dSmrg		DBG(("%s(pixmap=%ld) -- no, has palette\n", __FUNCTION__,
129428d7b3dSmrg		     get_drawable_pixmap(dst->pDrawable)->drawable.serialNumber));
130428d7b3dSmrg		return false;
131428d7b3dSmrg	default:
132428d7b3dSmrg		break;
133428d7b3dSmrg	}
134428d7b3dSmrg
135428d7b3dSmrg	return true;
136428d7b3dSmrg}
137428d7b3dSmrg
138428d7b3dSmrg
139428d7b3dSmrgstatic inline bool
140428d7b3dSmrgis_gpu_dst(struct sna_pixmap *priv)
141428d7b3dSmrg{
142428d7b3dSmrg	assert(priv);
143428d7b3dSmrg
144428d7b3dSmrg	if (too_small(priv))
145428d7b3dSmrg		return false;
146428d7b3dSmrg
147428d7b3dSmrg	if (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo))
148428d7b3dSmrg		return true;
149428d7b3dSmrg
150428d7b3dSmrg	if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo))
151428d7b3dSmrg		return true;
152428d7b3dSmrg
153428d7b3dSmrg	if (DAMAGE_IS_ALL(priv->cpu_damage))
154428d7b3dSmrg		return false;
155428d7b3dSmrg
156428d7b3dSmrg	return priv->gpu_damage != NULL || !priv->cpu;
157428d7b3dSmrg}
158428d7b3dSmrg
159428d7b3dSmrgstatic inline bool
160428d7b3dSmrgunattached(DrawablePtr drawable)
161428d7b3dSmrg{
162428d7b3dSmrg	struct sna_pixmap *priv = sna_pixmap_from_drawable(drawable);
163428d7b3dSmrg	return priv == NULL || (priv->gpu_damage == NULL && priv->cpu_damage && !priv->cpu_bo);
164428d7b3dSmrg}
165428d7b3dSmrg
166428d7b3dSmrgstatic inline bool
167428d7b3dSmrgpicture_is_gpu(struct sna *sna, PicturePtr picture, unsigned flags)
168428d7b3dSmrg{
169428d7b3dSmrg	if (!picture)
170428d7b3dSmrg		return false;
171428d7b3dSmrg
172428d7b3dSmrg	if (!picture->pDrawable) {
173428d7b3dSmrg		switch (flags) {
174428d7b3dSmrg		case PREFER_GPU_RENDER:
175428d7b3dSmrg			switch (picture->pSourcePict->type) {
176428d7b3dSmrg			case SourcePictTypeSolidFill:
177428d7b3dSmrg			case SourcePictTypeLinear:
178428d7b3dSmrg				return false;
179428d7b3dSmrg			default:
180428d7b3dSmrg				return true;
181428d7b3dSmrg			}
182428d7b3dSmrg		case PREFER_GPU_SPANS:
183428d7b3dSmrg			return true;
184428d7b3dSmrg		default:
185428d7b3dSmrg			return false;
186428d7b3dSmrg		}
187428d7b3dSmrg	} else {
188428d7b3dSmrg		if (picture->repeat &&
189428d7b3dSmrg		    (picture->pDrawable->width | picture->pDrawable->height) == 1)
190428d7b3dSmrg			return flags == PREFER_GPU_SPANS;
191428d7b3dSmrg	}
192428d7b3dSmrg
193428d7b3dSmrg	return is_gpu(sna, picture->pDrawable, flags);
194428d7b3dSmrg}
195428d7b3dSmrg
196428d7b3dSmrgstatic inline bool
197428d7b3dSmrgpicture_is_cpu(struct sna *sna, PicturePtr picture)
198428d7b3dSmrg{
199428d7b3dSmrg	if (!picture->pDrawable)
200428d7b3dSmrg		return false;
201428d7b3dSmrg
202428d7b3dSmrg	return !is_gpu(sna, picture->pDrawable, PREFER_GPU_RENDER);
203428d7b3dSmrg}
204428d7b3dSmrg
205428d7b3dSmrgstatic inline bool sna_blt_compare_depth(const DrawableRec *src, const DrawableRec *dst)
206428d7b3dSmrg{
207428d7b3dSmrg	if (src->depth == dst->depth)
208428d7b3dSmrg		return true;
209428d7b3dSmrg
210428d7b3dSmrg	/* Also allow for the alpha to be discarded on a copy */
211428d7b3dSmrg	if (src->bitsPerPixel != dst->bitsPerPixel)
212428d7b3dSmrg		return false;
213428d7b3dSmrg
214428d7b3dSmrg	if (dst->depth == 24 && src->depth == 32)
215428d7b3dSmrg		return true;
216428d7b3dSmrg
217428d7b3dSmrg	/* Note that a depth-16 pixmap is r5g6b5, not x1r5g5b5. */
218428d7b3dSmrg
219428d7b3dSmrg	return false;
220428d7b3dSmrg}
221428d7b3dSmrg
222428d7b3dSmrgstatic inline struct kgem_bo *
223428d7b3dSmrgsna_render_get_alpha_gradient(struct sna *sna)
224428d7b3dSmrg{
225428d7b3dSmrg	return kgem_bo_reference(sna->render.alpha_cache.cache_bo);
226428d7b3dSmrg}
227428d7b3dSmrg
228428d7b3dSmrgstatic inline void
229428d7b3dSmrgsna_render_picture_extents(PicturePtr p, BoxRec *box)
230428d7b3dSmrg{
231428d7b3dSmrg	box->x1 = p->pDrawable->x;
232428d7b3dSmrg	box->y1 = p->pDrawable->y;
233428d7b3dSmrg	box->x2 = bound(box->x1, p->pDrawable->width);
234428d7b3dSmrg	box->y2 = bound(box->y1, p->pDrawable->height);
235428d7b3dSmrg
236428d7b3dSmrg	if (box->x1 < p->pCompositeClip->extents.x1)
237428d7b3dSmrg		box->x1 = p->pCompositeClip->extents.x1;
238428d7b3dSmrg	if (box->y1 < p->pCompositeClip->extents.y1)
239428d7b3dSmrg		box->y1 = p->pCompositeClip->extents.y1;
240428d7b3dSmrg
241428d7b3dSmrg	if (box->x2 > p->pCompositeClip->extents.x2)
242428d7b3dSmrg		box->x2 = p->pCompositeClip->extents.x2;
243428d7b3dSmrg	if (box->y2 > p->pCompositeClip->extents.y2)
244428d7b3dSmrg		box->y2 = p->pCompositeClip->extents.y2;
245428d7b3dSmrg
246428d7b3dSmrg	assert(box->x2 > box->x1 && box->y2 > box->y1);
247428d7b3dSmrg}
248428d7b3dSmrg
249428d7b3dSmrgstatic inline void
250428d7b3dSmrgsna_render_reduce_damage(struct sna_composite_op *op,
251428d7b3dSmrg			 int dst_x, int dst_y,
252428d7b3dSmrg			 int width, int height)
253428d7b3dSmrg{
254428d7b3dSmrg	BoxRec r;
255428d7b3dSmrg
256428d7b3dSmrg	if (op->damage == NULL || *op->damage == NULL)
257428d7b3dSmrg		return;
258428d7b3dSmrg
259428d7b3dSmrg	if (DAMAGE_IS_ALL(*op->damage)) {
260428d7b3dSmrg		DBG(("%s: damage-all, dicarding damage\n",
261428d7b3dSmrg		     __FUNCTION__));
262428d7b3dSmrg		op->damage = NULL;
263428d7b3dSmrg		return;
264428d7b3dSmrg	}
265428d7b3dSmrg
266428d7b3dSmrg	if (width == 0 || height == 0)
267428d7b3dSmrg		return;
268428d7b3dSmrg
269428d7b3dSmrg	r.x1 = dst_x + op->dst.x;
270428d7b3dSmrg	r.x2 = r.x1 + width;
271428d7b3dSmrg
272428d7b3dSmrg	r.y1 = dst_y + op->dst.y;
273428d7b3dSmrg	r.y2 = r.y1 + height;
274428d7b3dSmrg
275428d7b3dSmrg	if (sna_damage_contains_box__no_reduce(*op->damage, &r)) {
276428d7b3dSmrg		DBG(("%s: damage contains render extents, dicarding damage\n",
277428d7b3dSmrg		     __FUNCTION__));
278428d7b3dSmrg		op->damage = NULL;
279428d7b3dSmrg	}
280428d7b3dSmrg}
281428d7b3dSmrg
282428d7b3dSmrginline static uint32_t
283428d7b3dSmrgcolor_convert(uint32_t pixel,
284428d7b3dSmrg	      uint32_t src_format,
285428d7b3dSmrg	      uint32_t dst_format)
286428d7b3dSmrg{
287428d7b3dSmrg	DBG(("%s: src=%08x [%08x]\n", __FUNCTION__, pixel, src_format));
288428d7b3dSmrg
289428d7b3dSmrg	if (src_format != dst_format) {
290428d7b3dSmrg		uint16_t red, green, blue, alpha;
291428d7b3dSmrg
292428d7b3dSmrg		if (!sna_get_rgba_from_pixel(pixel,
293428d7b3dSmrg					     &red, &green, &blue, &alpha,
294428d7b3dSmrg					     src_format))
295428d7b3dSmrg			return 0;
296428d7b3dSmrg
297428d7b3dSmrg		if (!sna_get_pixel_from_rgba(&pixel,
298428d7b3dSmrg					     red, green, blue, alpha,
299428d7b3dSmrg					     dst_format))
300428d7b3dSmrg			return 0;
301428d7b3dSmrg	}
302428d7b3dSmrg
303428d7b3dSmrg	DBG(("%s: dst=%08x [%08x]\n", __FUNCTION__, pixel, dst_format));
304428d7b3dSmrg	return pixel;
305428d7b3dSmrg}
306428d7b3dSmrg
307428d7b3dSmrginline static bool dst_use_gpu(PixmapPtr pixmap)
308428d7b3dSmrg{
309428d7b3dSmrg	struct sna_pixmap *priv = sna_pixmap(pixmap);
310428d7b3dSmrg	if (priv == NULL)
311428d7b3dSmrg		return false;
312428d7b3dSmrg
313428d7b3dSmrg	if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo))
314428d7b3dSmrg		return true;
315428d7b3dSmrg
316428d7b3dSmrg	if (priv->clear)
317428d7b3dSmrg		return false;
318428d7b3dSmrg
319428d7b3dSmrg	if (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo))
320428d7b3dSmrg		return true;
321428d7b3dSmrg
322428d7b3dSmrg	return priv->gpu_damage && (!priv->cpu || !priv->cpu_damage);
323428d7b3dSmrg}
324428d7b3dSmrg
325428d7b3dSmrginline static bool dst_use_cpu(PixmapPtr pixmap)
326428d7b3dSmrg{
327428d7b3dSmrg	struct sna_pixmap *priv = sna_pixmap(pixmap);
328428d7b3dSmrg	if (priv == NULL || priv->shm)
329428d7b3dSmrg		return true;
330428d7b3dSmrg
331428d7b3dSmrg	return priv->cpu_damage && priv->cpu;
332428d7b3dSmrg}
333428d7b3dSmrg
334428d7b3dSmrginline static bool dst_is_cpu(PixmapPtr pixmap)
335428d7b3dSmrg{
336428d7b3dSmrg	struct sna_pixmap *priv = sna_pixmap(pixmap);
337428d7b3dSmrg	return priv == NULL || DAMAGE_IS_ALL(priv->cpu_damage);
338428d7b3dSmrg}
339428d7b3dSmrg
340428d7b3dSmrginline static bool
341428d7b3dSmrguntransformed(PicturePtr p)
342428d7b3dSmrg{
343428d7b3dSmrg	return !p->transform || pixman_transform_is_int_translate(p->transform);
344428d7b3dSmrg}
345428d7b3dSmrg
346428d7b3dSmrginline static void
347428d7b3dSmrgboxes_extents(const BoxRec *box, int n, BoxRec *extents)
348428d7b3dSmrg{
349428d7b3dSmrg	*extents = box[0];
350428d7b3dSmrg	while (--n) {
351428d7b3dSmrg		box++;
352428d7b3dSmrg
353428d7b3dSmrg		if (box->x1 < extents->x1)
354428d7b3dSmrg			extents->x1 = box->x1;
355428d7b3dSmrg		if (box->x2 > extents->x2)
356428d7b3dSmrg			extents->x2 = box->x2;
357428d7b3dSmrg
358428d7b3dSmrg		if (box->y1 < extents->y1)
359428d7b3dSmrg			extents->y1 = box->y1;
360428d7b3dSmrg		if (box->y2 > extents->y2)
361428d7b3dSmrg			extents->y2 = box->y2;
362428d7b3dSmrg	}
363428d7b3dSmrg}
364428d7b3dSmrg
365428d7b3dSmrginline static bool
366428d7b3dSmrgoverlaps(struct sna *sna,
367428d7b3dSmrg	 struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy,
368428d7b3dSmrg	 struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy,
369428d7b3dSmrg	 const BoxRec *box, int n, unsigned flags,
370428d7b3dSmrg	 BoxRec *extents)
371428d7b3dSmrg{
372428d7b3dSmrg	if (src_bo != dst_bo)
373428d7b3dSmrg		return false;
374428d7b3dSmrg
375428d7b3dSmrg	if (flags & COPY_NO_OVERLAP)
376428d7b3dSmrg		return false;
377428d7b3dSmrg
378428d7b3dSmrg	boxes_extents(box, n, extents);
379428d7b3dSmrg	return (extents->x2 + src_dx > extents->x1 + dst_dx &&
380428d7b3dSmrg		extents->x1 + src_dx < extents->x2 + dst_dx &&
381428d7b3dSmrg		extents->y2 + src_dy > extents->y1 + dst_dy &&
382428d7b3dSmrg		extents->y1 + src_dy < extents->y2 + dst_dy);
383428d7b3dSmrg}
384428d7b3dSmrg
385428d7b3dSmrgstatic inline long get_picture_id(PicturePtr picture)
386428d7b3dSmrg{
387428d7b3dSmrg	return picture && picture->pDrawable ? get_drawable_pixmap(picture->pDrawable)->drawable.serialNumber : 0;
388428d7b3dSmrg}
389428d7b3dSmrg
390428d7b3dSmrg#endif /* SNA_RENDER_INLINE_H */
391