xorg_composite.c revision ecfe1352ccce802c9299c76d600c4d2f33352701
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
15struct 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
26static 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
56static INLINE void
57pixel_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
71static boolean
72blend_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
116static INLINE int
117render_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
134static INLINE boolean
135render_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
166static 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
174boolean 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
211static void
212bind_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
234static unsigned
235picture_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
296static void
297bind_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
352static void
353bind_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
427
428static INLINE boolean matrix_from_pict_transform(PictTransform *trans, float *matrix)
429{
430   if (!trans)
431      return FALSE;
432
433   matrix[0] = XFixedToDouble(trans->matrix[0][0]);
434   matrix[3] = XFixedToDouble(trans->matrix[0][1]);
435   matrix[6] = XFixedToDouble(trans->matrix[0][2]);
436
437   matrix[1] = XFixedToDouble(trans->matrix[1][0]);
438   matrix[4] = XFixedToDouble(trans->matrix[1][1]);
439   matrix[7] = XFixedToDouble(trans->matrix[1][2]);
440
441   matrix[2] = XFixedToDouble(trans->matrix[2][0]);
442   matrix[5] = XFixedToDouble(trans->matrix[2][1]);
443   matrix[8] = XFixedToDouble(trans->matrix[2][2]);
444
445   return TRUE;
446}
447
448static void
449setup_transforms(struct  exa_context *exa,
450                 PicturePtr pSrcPicture, PicturePtr pMaskPicture)
451{
452   PictTransform *src_t = NULL;
453   PictTransform *mask_t = NULL;
454
455   if (pSrcPicture)
456      src_t = pSrcPicture->transform;
457   if (pMaskPicture)
458      mask_t = pMaskPicture->transform;
459
460   exa->transform.has_src  =
461      matrix_from_pict_transform(src_t, exa->transform.src);
462   exa->transform.has_mask =
463      matrix_from_pict_transform(mask_t, exa->transform.mask);
464}
465
466boolean xorg_composite_bind_state(struct exa_context *exa,
467                                  int op,
468                                  PicturePtr pSrcPicture,
469                                  PicturePtr pMaskPicture,
470                                  PicturePtr pDstPicture,
471                                  struct exa_pixmap_priv *pSrc,
472                                  struct exa_pixmap_priv *pMask,
473                                  struct exa_pixmap_priv *pDst)
474{
475   struct pipe_surface *dst_surf = xorg_gpu_surface(exa->scrn, pDst);
476
477   renderer_bind_destination(exa->renderer, dst_surf);
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
499void 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
526boolean 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   bind_blend_state(exa, PictOpSrc, NULL, NULL, NULL);
550   cso_set_samplers(exa->renderer->cso, 0, NULL);
551   cso_set_sampler_textures(exa->renderer->cso, 0, NULL);
552
553   shader = xorg_shaders_get(exa->renderer->shaders, vs_traits, fs_traits);
554   cso_set_vertex_shader_handle(exa->renderer->cso, shader.vs);
555   cso_set_fragment_shader_handle(exa->renderer->cso, shader.fs);
556
557   renderer_begin_solid(exa->renderer);
558
559   pipe_surface_reference(&dst_surf, NULL);
560   return TRUE;
561}
562
563void xorg_solid(struct exa_context *exa,
564                struct exa_pixmap_priv *pixmap,
565                int x0, int y0, int x1, int y1)
566{
567   renderer_solid(exa->renderer,
568                  x0, y0, x1, y1, exa->solid_color);
569}
570
571void
572xorg_composite_done(struct exa_context *exa)
573{
574   renderer_draw_flush(exa->renderer);
575
576   exa->transform.has_src = FALSE;
577   exa->transform.has_mask = FALSE;
578   exa->has_solid_color = FALSE;
579   exa->num_bound_samplers = 0;
580}
581