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