mesa: Add "shader/" path to #include statements in shader parser/lexer sources
[mesa.git] / src / gallium / state_trackers / xorg / xorg_composite.c
1 #include "xorg_composite.h"
2
3 #include "xorg_renderer.h"
4 #include "xorg_exa_tgsi.h"
5
6 #include "cso_cache/cso_context.h"
7 #include "util/u_draw_quad.h"
8 #include "util/u_math.h"
9
10 #include "pipe/p_inlines.h"
11
12 /*XXX also in Xrender.h but the including it here breaks compilition */
13 #define XFixedToDouble(f) (((double) (f)) / 65536.)
14
15 struct xorg_composite_blend {
16 int op : 8;
17
18 unsigned alpha_dst : 4;
19 unsigned alpha_src : 4;
20
21 unsigned rgb_src : 8; /**< PIPE_BLENDFACTOR_x */
22 unsigned rgb_dst : 8; /**< PIPE_BLENDFACTOR_x */
23 };
24
25 #define BLEND_OP_OVER 3
26 static const struct xorg_composite_blend xorg_blends[] = {
27 { PictOpClear,
28 0, 0, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO},
29 { PictOpSrc,
30 0, 0, PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ZERO},
31 { PictOpDst,
32 0, 0, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ONE},
33 { PictOpOver,
34 0, 1, PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_INV_SRC_ALPHA},
35 { PictOpOverReverse,
36 1, 0, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_ONE},
37 { PictOpIn,
38 1, 0, PIPE_BLENDFACTOR_DST_ALPHA, PIPE_BLENDFACTOR_ZERO},
39 { PictOpInReverse,
40 0, 1, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_SRC_ALPHA},
41 { PictOpOut,
42 1, 0, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_ZERO},
43 { PictOpOutReverse,
44 0, 1, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_INV_SRC_ALPHA},
45 { PictOpAtop,
46 1, 1, PIPE_BLENDFACTOR_DST_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA},
47 { PictOpAtopReverse,
48 1, 1, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_SRC_ALPHA},
49 { PictOpXor,
50 1, 1, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA},
51 { PictOpAdd,
52 0, 0, PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ONE},
53 };
54
55
56 static INLINE void
57 pixel_to_float4(Pixel pixel, float *color)
58 {
59 CARD32 r, g, b, a;
60
61 a = (pixel >> 24) & 0xff;
62 r = (pixel >> 16) & 0xff;
63 g = (pixel >> 8) & 0xff;
64 b = (pixel >> 0) & 0xff;
65 color[0] = ((float)r) / 255.;
66 color[1] = ((float)g) / 255.;
67 color[2] = ((float)b) / 255.;
68 color[3] = ((float)a) / 255.;
69 }
70
71 static boolean
72 blend_for_op(struct xorg_composite_blend *blend,
73 int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
74 PicturePtr pDstPicture)
75 {
76 const int num_blends =
77 sizeof(xorg_blends)/sizeof(struct xorg_composite_blend);
78 int i;
79 boolean supported = FALSE;
80
81 /* our default in case something goes wrong */
82 *blend = xorg_blends[BLEND_OP_OVER];
83
84 for (i = 0; i < num_blends; ++i) {
85 if (xorg_blends[i].op == op) {
86 *blend = xorg_blends[i];
87 supported = TRUE;
88 }
89 }
90
91 /* If there's no dst alpha channel, adjust the blend op so that we'll treat
92 * it as always 1. */
93 if (pDstPicture &&
94 PICT_FORMAT_A(pDstPicture->format) == 0 && blend->alpha_dst) {
95 if (blend->rgb_src == PIPE_BLENDFACTOR_DST_ALPHA)
96 blend->rgb_src = PIPE_BLENDFACTOR_ONE;
97 else if (blend->rgb_src == PIPE_BLENDFACTOR_INV_DST_ALPHA)
98 blend->rgb_src = PIPE_BLENDFACTOR_ZERO;
99 }
100
101 /* If the source alpha is being used, then we should only be in a case where
102 * the source blend factor is 0, and the source blend value is the mask
103 * channels multiplied by the source picture's alpha. */
104 if (pMaskPicture && pMaskPicture->componentAlpha &&
105 PICT_FORMAT_RGB(pMaskPicture->format) && blend->alpha_src) {
106 if (blend->rgb_dst == PIPE_BLENDFACTOR_SRC_ALPHA) {
107 blend->rgb_dst = PIPE_BLENDFACTOR_SRC_COLOR;
108 } else if (blend->rgb_dst == PIPE_BLENDFACTOR_INV_SRC_ALPHA) {
109 blend->rgb_dst = PIPE_BLENDFACTOR_INV_SRC_COLOR;
110 }
111 }
112
113 return supported;
114 }
115
116 static INLINE int
117 render_repeat_to_gallium(int mode)
118 {
119 switch(mode) {
120 case RepeatNone:
121 return PIPE_TEX_WRAP_CLAMP_TO_BORDER;
122 case RepeatNormal:
123 return PIPE_TEX_WRAP_REPEAT;
124 case RepeatReflect:
125 return PIPE_TEX_WRAP_MIRROR_REPEAT;
126 case RepeatPad:
127 return PIPE_TEX_WRAP_CLAMP_TO_EDGE;
128 default:
129 debug_printf("Unsupported repeat mode\n");
130 }
131 return PIPE_TEX_WRAP_REPEAT;
132 }
133
134 static INLINE boolean
135 render_filter_to_gallium(int xrender_filter, int *out_filter)
136 {
137
138 switch (xrender_filter) {
139 case PictFilterNearest:
140 *out_filter = PIPE_TEX_FILTER_NEAREST;
141 break;
142 case PictFilterBilinear:
143 *out_filter = PIPE_TEX_FILTER_LINEAR;
144 break;
145 case PictFilterFast:
146 *out_filter = PIPE_TEX_FILTER_NEAREST;
147 break;
148 case PictFilterGood:
149 *out_filter = PIPE_TEX_FILTER_LINEAR;
150 break;
151 case PictFilterBest:
152 *out_filter = PIPE_TEX_FILTER_LINEAR;
153 break;
154 case PictFilterConvolution:
155 *out_filter = PIPE_TEX_FILTER_NEAREST;
156 return FALSE;
157 default:
158 debug_printf("Unknown xrender filter\n");
159 *out_filter = PIPE_TEX_FILTER_NEAREST;
160 return FALSE;
161 }
162
163 return TRUE;
164 }
165
166 static boolean is_filter_accelerated(PicturePtr pic)
167 {
168 int filter;
169 if (pic && !render_filter_to_gallium(pic->filter, &filter))
170 return FALSE;
171 return TRUE;
172 }
173
174 boolean xorg_composite_accelerated(int op,
175 PicturePtr pSrcPicture,
176 PicturePtr pMaskPicture,
177 PicturePtr pDstPicture)
178 {
179 ScreenPtr pScreen = pDstPicture->pDrawable->pScreen;
180 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
181 modesettingPtr ms = modesettingPTR(pScrn);
182 struct xorg_composite_blend blend;
183
184 if (!is_filter_accelerated(pSrcPicture) ||
185 !is_filter_accelerated(pMaskPicture)) {
186 XORG_FALLBACK("Unsupported Xrender filter");
187 }
188
189 if (pSrcPicture->pSourcePict) {
190 if (pSrcPicture->pSourcePict->type != SourcePictTypeSolidFill)
191 XORG_FALLBACK("Gradients not enabled (haven't been well tested)");
192 }
193
194 if (blend_for_op(&blend, op,
195 pSrcPicture, pMaskPicture, pDstPicture)) {
196 /* Check for component alpha */
197 if (pMaskPicture && pMaskPicture->componentAlpha &&
198 PICT_FORMAT_RGB(pMaskPicture->format)) {
199 if (blend.alpha_src && blend.rgb_src != PIPE_BLENDFACTOR_ZERO) {
200 XORG_FALLBACK("Component alpha not supported with source "
201 "alpha and source value blending. (op=%d)",
202 op);
203 }
204 }
205
206 return TRUE;
207 }
208 XORG_FALLBACK("Unsupported composition operation = %d", op);
209 }
210
211 static void
212 bind_blend_state(struct exa_context *exa, int op,
213 PicturePtr pSrcPicture,
214 PicturePtr pMaskPicture,
215 PicturePtr pDstPicture)
216 {
217 struct xorg_composite_blend blend_opt;
218 struct pipe_blend_state blend;
219
220 blend_for_op(&blend_opt, op, pSrcPicture, pMaskPicture, pDstPicture);
221
222 memset(&blend, 0, sizeof(struct pipe_blend_state));
223 blend.blend_enable = 1;
224 blend.colormask |= PIPE_MASK_RGBA;
225
226 blend.rgb_src_factor = blend_opt.rgb_src;
227 blend.alpha_src_factor = blend_opt.rgb_src;
228 blend.rgb_dst_factor = blend_opt.rgb_dst;
229 blend.alpha_dst_factor = blend_opt.rgb_dst;
230
231 cso_set_blend(exa->renderer->cso, &blend);
232 }
233
234 static unsigned
235 picture_format_fixups(struct exa_pixmap_priv *pSrc, PicturePtr pSrcPicture, boolean mask,
236 PicturePtr pDstPicture)
237 {
238 boolean set_alpha = FALSE;
239 boolean swizzle = FALSE;
240 unsigned ret = 0;
241
242 if (pSrc->picture_format == pSrcPicture->format) {
243 if (pSrc->picture_format == PICT_a8) {
244 if (mask)
245 return FS_MASK_LUMINANCE;
246 else if (pDstPicture->format != PICT_a8) {
247 /* if both dst and src are luminance then
248 * we don't want to swizzle the alpha (X) of the
249 * source into W component of the dst because
250 * it will break our destination */
251 return FS_SRC_LUMINANCE;
252 }
253 }
254 return 0;
255 }
256
257 if (pSrc->picture_format != PICT_a8r8g8b8) {
258 assert(!"can not handle formats");
259 return 0;
260 }
261
262 /* pSrc->picture_format == PICT_a8r8g8b8 */
263 switch (pSrcPicture->format) {
264 case PICT_x8b8g8r8:
265 case PICT_b8g8r8:
266 set_alpha = TRUE; /* fall trough */
267 case PICT_a8b8g8r8:
268 swizzle = TRUE;
269 break;
270 case PICT_x8r8g8b8:
271 case PICT_r8g8b8:
272 set_alpha = TRUE; /* fall through */
273 case PICT_a8r8g8b8:
274 break;
275 #ifdef PICT_TYPE_BGRA
276 case PICT_b8g8r8a8:
277 case PICT_b8g8r8x8:
278 case PICT_a2r10g10b10:
279 case PICT_x2r10g10b10:
280 case PICT_a2b10g10r10:
281 case PICT_x2b10g10r10:
282 #endif
283 default:
284 assert(!"can not handle formats");
285 return 0;
286 }
287
288 if (set_alpha)
289 ret |= mask ? FS_MASK_SET_ALPHA : FS_SRC_SET_ALPHA;
290 if (swizzle)
291 ret |= mask ? FS_MASK_SWIZZLE_RGB : FS_SRC_SWIZZLE_RGB;
292
293 return ret;
294 }
295
296 static void
297 bind_shaders(struct exa_context *exa, int op,
298 PicturePtr pSrcPicture, PicturePtr pMaskPicture, PicturePtr pDstPicture,
299 struct exa_pixmap_priv *pSrc, struct exa_pixmap_priv *pMask)
300 {
301 unsigned vs_traits = 0, fs_traits = 0;
302 struct xorg_shader shader;
303
304 exa->has_solid_color = FALSE;
305
306 if (pSrcPicture) {
307 if (pSrcPicture->repeatType == RepeatNone && pSrcPicture->transform)
308 fs_traits |= FS_SRC_REPEAT_NONE;
309
310 if (pSrcPicture->pSourcePict) {
311 if (pSrcPicture->pSourcePict->type == SourcePictTypeSolidFill) {
312 fs_traits |= FS_SOLID_FILL;
313 vs_traits |= VS_SOLID_FILL;
314 debug_assert(pSrcPicture->format == PICT_a8r8g8b8);
315 pixel_to_float4(pSrcPicture->pSourcePict->solidFill.color,
316 exa->solid_color);
317 exa->has_solid_color = TRUE;
318 } else {
319 debug_assert("!gradients not supported");
320 }
321 } else {
322 fs_traits |= FS_COMPOSITE;
323 vs_traits |= VS_COMPOSITE;
324 }
325
326 fs_traits |= picture_format_fixups(pSrc, pSrcPicture, FALSE, pDstPicture);
327 }
328
329 if (pMaskPicture) {
330 vs_traits |= VS_MASK;
331 fs_traits |= FS_MASK;
332 if (pMaskPicture->repeatType == RepeatNone && pMaskPicture->transform)
333 fs_traits |= FS_MASK_REPEAT_NONE;
334 if (pMaskPicture->componentAlpha) {
335 struct xorg_composite_blend blend;
336 blend_for_op(&blend, op,
337 pSrcPicture, pMaskPicture, NULL);
338 if (blend.alpha_src) {
339 fs_traits |= FS_CA_SRCALPHA;
340 } else
341 fs_traits |= FS_CA_FULL;
342 }
343
344 fs_traits |= picture_format_fixups(pMask, pMaskPicture, TRUE, pDstPicture);
345 }
346
347 shader = xorg_shaders_get(exa->renderer->shaders, vs_traits, fs_traits);
348 cso_set_vertex_shader_handle(exa->renderer->cso, shader.vs);
349 cso_set_fragment_shader_handle(exa->renderer->cso, shader.fs);
350 }
351
352 static void
353 bind_samplers(struct exa_context *exa, int op,
354 PicturePtr pSrcPicture, PicturePtr pMaskPicture,
355 PicturePtr pDstPicture,
356 struct exa_pixmap_priv *pSrc,
357 struct exa_pixmap_priv *pMask,
358 struct exa_pixmap_priv *pDst)
359 {
360 struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS];
361 struct pipe_sampler_state src_sampler, mask_sampler;
362
363 exa->num_bound_samplers = 0;
364
365 #if 0
366 if ((pSrc && (exa->pipe->is_texture_referenced(exa->pipe, pSrc->tex, 0, 0) &
367 PIPE_REFERENCED_FOR_WRITE)) ||
368 (pMask && (exa->pipe->is_texture_referenced(exa->pipe, pMask->tex, 0, 0) &
369 PIPE_REFERENCED_FOR_WRITE)))
370 xorg_exa_flush(exa, PIPE_FLUSH_RENDER_CACHE, NULL);
371 #endif
372
373 memset(&src_sampler, 0, sizeof(struct pipe_sampler_state));
374 memset(&mask_sampler, 0, sizeof(struct pipe_sampler_state));
375
376 if (pSrcPicture && pSrc) {
377 if (exa->has_solid_color) {
378 debug_assert(!"solid color with textures");
379 samplers[0] = NULL;
380 exa->bound_textures[0] = NULL;
381 } else {
382 unsigned src_wrap = render_repeat_to_gallium(
383 pSrcPicture->repeatType);
384 int filter;
385
386 render_filter_to_gallium(pSrcPicture->filter, &filter);
387
388 src_sampler.wrap_s = src_wrap;
389 src_sampler.wrap_t = src_wrap;
390 src_sampler.min_img_filter = filter;
391 src_sampler.mag_img_filter = filter;
392 src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST;
393 src_sampler.normalized_coords = 1;
394 samplers[0] = &src_sampler;
395 exa->bound_textures[0] = pSrc->tex;
396 exa->num_bound_samplers = 1;
397 }
398 }
399
400 if (pMaskPicture && pMask) {
401 unsigned mask_wrap = render_repeat_to_gallium(
402 pMaskPicture->repeatType);
403 int filter;
404
405 render_filter_to_gallium(pMaskPicture->filter, &filter);
406
407 mask_sampler.wrap_s = mask_wrap;
408 mask_sampler.wrap_t = mask_wrap;
409 mask_sampler.min_img_filter = filter;
410 mask_sampler.mag_img_filter = filter;
411 src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST;
412 mask_sampler.normalized_coords = 1;
413 samplers[1] = &mask_sampler;
414 exa->bound_textures[1] = pMask->tex;
415 exa->num_bound_samplers = 2;
416 }
417
418 cso_set_samplers(exa->renderer->cso, exa->num_bound_samplers,
419 (const struct pipe_sampler_state **)samplers);
420 cso_set_sampler_textures(exa->renderer->cso, exa->num_bound_samplers,
421 exa->bound_textures);
422 }
423
424
425
426 static INLINE boolean matrix_from_pict_transform(PictTransform *trans, float *matrix)
427 {
428 if (!trans)
429 return FALSE;
430
431 matrix[0] = XFixedToDouble(trans->matrix[0][0]);
432 matrix[3] = XFixedToDouble(trans->matrix[0][1]);
433 matrix[6] = XFixedToDouble(trans->matrix[0][2]);
434
435 matrix[1] = XFixedToDouble(trans->matrix[1][0]);
436 matrix[4] = XFixedToDouble(trans->matrix[1][1]);
437 matrix[7] = XFixedToDouble(trans->matrix[1][2]);
438
439 matrix[2] = XFixedToDouble(trans->matrix[2][0]);
440 matrix[5] = XFixedToDouble(trans->matrix[2][1]);
441 matrix[8] = XFixedToDouble(trans->matrix[2][2]);
442
443 return TRUE;
444 }
445
446 static void
447 setup_transforms(struct exa_context *exa,
448 PicturePtr pSrcPicture, PicturePtr pMaskPicture)
449 {
450 PictTransform *src_t = NULL;
451 PictTransform *mask_t = NULL;
452
453 if (pSrcPicture)
454 src_t = pSrcPicture->transform;
455 if (pMaskPicture)
456 mask_t = pMaskPicture->transform;
457
458 exa->transform.has_src =
459 matrix_from_pict_transform(src_t, exa->transform.src);
460 exa->transform.has_mask =
461 matrix_from_pict_transform(mask_t, exa->transform.mask);
462 }
463
464 boolean xorg_composite_bind_state(struct exa_context *exa,
465 int op,
466 PicturePtr pSrcPicture,
467 PicturePtr pMaskPicture,
468 PicturePtr pDstPicture,
469 struct exa_pixmap_priv *pSrc,
470 struct exa_pixmap_priv *pMask,
471 struct exa_pixmap_priv *pDst)
472 {
473 struct pipe_surface *dst_surf = xorg_gpu_surface(exa->scrn, pDst);
474
475 renderer_bind_destination(exa->renderer, dst_surf,
476 pDst->width,
477 pDst->height);
478
479 bind_blend_state(exa, op, pSrcPicture, pMaskPicture, pDstPicture);
480 bind_shaders(exa, op, pSrcPicture, pMaskPicture, pDstPicture, pSrc, pMask);
481 bind_samplers(exa, op, pSrcPicture, pMaskPicture,
482 pDstPicture, pSrc, pMask, pDst);
483
484 setup_transforms(exa, pSrcPicture, pMaskPicture);
485
486 if (exa->num_bound_samplers == 0 ) { /* solid fill */
487 renderer_begin_solid(exa->renderer);
488 } else {
489 renderer_begin_textures(exa->renderer,
490 exa->bound_textures,
491 exa->num_bound_samplers);
492 }
493
494
495 pipe_surface_reference(&dst_surf, NULL);
496 return TRUE;
497 }
498
499 void xorg_composite(struct exa_context *exa,
500 struct exa_pixmap_priv *dst,
501 int srcX, int srcY, int maskX, int maskY,
502 int dstX, int dstY, int width, int height)
503 {
504 if (exa->num_bound_samplers == 0 ) { /* solid fill */
505 renderer_solid(exa->renderer,
506 dstX, dstY, dstX + width, dstY + height,
507 exa->solid_color);
508 } else {
509 int pos[6] = {srcX, srcY, maskX, maskY, dstX, dstY};
510 float *src_matrix = NULL;
511 float *mask_matrix = NULL;
512
513 if (exa->transform.has_src)
514 src_matrix = exa->transform.src;
515 if (exa->transform.has_mask)
516 mask_matrix = exa->transform.mask;
517
518 renderer_texture(exa->renderer,
519 pos, width, height,
520 exa->bound_textures,
521 exa->num_bound_samplers,
522 src_matrix, mask_matrix);
523 }
524 }
525
526 boolean xorg_solid_bind_state(struct exa_context *exa,
527 struct exa_pixmap_priv *pixmap,
528 Pixel fg)
529 {
530 struct pipe_surface *dst_surf = xorg_gpu_surface(exa->scrn, pixmap);
531 unsigned vs_traits, fs_traits;
532 struct xorg_shader shader;
533
534 pixel_to_float4(fg, exa->solid_color);
535 exa->has_solid_color = TRUE;
536
537 #if 0
538 debug_printf("Color Pixel=(%d, %d, %d, %d), RGBA=(%f, %f, %f, %f)\n",
539 (fg >> 24) & 0xff, (fg >> 16) & 0xff,
540 (fg >> 8) & 0xff, (fg >> 0) & 0xff,
541 exa->solid_color[0], exa->solid_color[1],
542 exa->solid_color[2], exa->solid_color[3]);
543 #endif
544
545 vs_traits = VS_SOLID_FILL;
546 fs_traits = FS_SOLID_FILL;
547
548 renderer_bind_destination(exa->renderer, dst_surf,
549 pixmap->width, pixmap->height);
550 bind_blend_state(exa, PictOpSrc, NULL, NULL, NULL);
551 cso_set_samplers(exa->renderer->cso, 0, NULL);
552 cso_set_sampler_textures(exa->renderer->cso, 0, NULL);
553
554 shader = xorg_shaders_get(exa->renderer->shaders, vs_traits, fs_traits);
555 cso_set_vertex_shader_handle(exa->renderer->cso, shader.vs);
556 cso_set_fragment_shader_handle(exa->renderer->cso, shader.fs);
557
558 renderer_begin_solid(exa->renderer);
559
560 pipe_surface_reference(&dst_surf, NULL);
561 return TRUE;
562 }
563
564 void xorg_solid(struct exa_context *exa,
565 struct exa_pixmap_priv *pixmap,
566 int x0, int y0, int x1, int y1)
567 {
568 renderer_solid(exa->renderer,
569 x0, y0, x1, y1, exa->solid_color);
570 }
571
572 void
573 xorg_composite_done(struct exa_context *exa)
574 {
575 renderer_draw_flush(exa->renderer);
576
577 exa->transform.has_src = FALSE;
578 exa->transform.has_mask = FALSE;
579 exa->has_solid_color = FALSE;
580 exa->num_bound_samplers = 0;
581 }