xorg_composite.c revision 9b346f83a7b672e913a7bb6a089d5dbd7fbdce06
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
12struct 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
23static 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
53static INLINE void
54pixel_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
68static boolean
69blend_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
113static INLINE int
114render_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
131static INLINE boolean
132render_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
163static 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
171boolean 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
208static void
209bind_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
231static unsigned
232picture_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
293static void
294bind_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
349static void
350bind_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#if 0
363   if ((pSrc && (exa->pipe->is_texture_referenced(exa->pipe, pSrc->tex, 0, 0) &
364                 PIPE_REFERENCED_FOR_WRITE)) ||
365       (pMask && (exa->pipe->is_texture_referenced(exa->pipe, pMask->tex, 0, 0) &
366        PIPE_REFERENCED_FOR_WRITE)))
367      xorg_exa_flush(exa, PIPE_FLUSH_RENDER_CACHE, NULL);
368#endif
369
370   memset(&src_sampler, 0, sizeof(struct pipe_sampler_state));
371   memset(&mask_sampler, 0, sizeof(struct pipe_sampler_state));
372
373   if (pSrcPicture && pSrc) {
374      if (exa->has_solid_color) {
375         debug_assert(!"solid color with textures");
376         samplers[0] = NULL;
377         exa->bound_textures[0] = NULL;
378      } else {
379         unsigned src_wrap = render_repeat_to_gallium(
380            pSrcPicture->repeatType);
381         int filter;
382
383         render_filter_to_gallium(pSrcPicture->filter, &filter);
384
385         src_sampler.wrap_s = src_wrap;
386         src_sampler.wrap_t = src_wrap;
387         src_sampler.min_img_filter = filter;
388         src_sampler.mag_img_filter = filter;
389         src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST;
390         src_sampler.normalized_coords = 1;
391         samplers[0] = &src_sampler;
392         exa->bound_textures[0] = pSrc->tex;
393         exa->num_bound_samplers = 1;
394      }
395   }
396
397   if (pMaskPicture && pMask) {
398      unsigned mask_wrap = render_repeat_to_gallium(
399         pMaskPicture->repeatType);
400      int filter;
401
402      render_filter_to_gallium(pMaskPicture->filter, &filter);
403
404      mask_sampler.wrap_s = mask_wrap;
405      mask_sampler.wrap_t = mask_wrap;
406      mask_sampler.min_img_filter = filter;
407      mask_sampler.mag_img_filter = filter;
408      src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST;
409      mask_sampler.normalized_coords = 1;
410      samplers[1] = &mask_sampler;
411      exa->bound_textures[1] = pMask->tex;
412      exa->num_bound_samplers = 2;
413   }
414
415   cso_set_samplers(exa->renderer->cso, exa->num_bound_samplers,
416                    (const struct pipe_sampler_state **)samplers);
417   cso_set_sampler_textures(exa->renderer->cso, exa->num_bound_samplers,
418                            exa->bound_textures);
419}
420
421
422
423static INLINE boolean matrix_from_pict_transform(PictTransform *trans, float *matrix)
424{
425   if (!trans)
426      return FALSE;
427
428   matrix[0] = XFixedToDouble(trans->matrix[0][0]);
429   matrix[3] = XFixedToDouble(trans->matrix[0][1]);
430   matrix[6] = XFixedToDouble(trans->matrix[0][2]);
431
432   matrix[1] = XFixedToDouble(trans->matrix[1][0]);
433   matrix[4] = XFixedToDouble(trans->matrix[1][1]);
434   matrix[7] = XFixedToDouble(trans->matrix[1][2]);
435
436   matrix[2] = XFixedToDouble(trans->matrix[2][0]);
437   matrix[5] = XFixedToDouble(trans->matrix[2][1]);
438   matrix[8] = XFixedToDouble(trans->matrix[2][2]);
439
440   return TRUE;
441}
442
443static void
444setup_transforms(struct  exa_context *exa,
445                 PicturePtr pSrcPicture, PicturePtr pMaskPicture)
446{
447   PictTransform *src_t = NULL;
448   PictTransform *mask_t = NULL;
449
450   if (pSrcPicture)
451      src_t = pSrcPicture->transform;
452   if (pMaskPicture)
453      mask_t = pMaskPicture->transform;
454
455   exa->transform.has_src  =
456      matrix_from_pict_transform(src_t, exa->transform.src);
457   exa->transform.has_mask =
458      matrix_from_pict_transform(mask_t, exa->transform.mask);
459}
460
461boolean xorg_composite_bind_state(struct exa_context *exa,
462                                  int op,
463                                  PicturePtr pSrcPicture,
464                                  PicturePtr pMaskPicture,
465                                  PicturePtr pDstPicture,
466                                  struct exa_pixmap_priv *pSrc,
467                                  struct exa_pixmap_priv *pMask,
468                                  struct exa_pixmap_priv *pDst)
469{
470   struct pipe_surface *dst_surf = xorg_gpu_surface(exa->scrn, pDst);
471
472   renderer_bind_destination(exa->renderer, dst_surf,
473                             pDst->width,
474                             pDst->height);
475
476   bind_blend_state(exa, op, pSrcPicture, pMaskPicture, pDstPicture);
477   bind_shaders(exa, op, pSrcPicture, pMaskPicture, pDstPicture, pSrc, pMask);
478   bind_samplers(exa, op, pSrcPicture, pMaskPicture,
479                 pDstPicture, pSrc, pMask, pDst);
480
481   setup_transforms(exa, pSrcPicture, pMaskPicture);
482
483   if (exa->num_bound_samplers == 0 ) { /* solid fill */
484      renderer_begin_solid(exa->renderer);
485   } else {
486      renderer_begin_textures(exa->renderer,
487                              exa->bound_textures,
488                              exa->num_bound_samplers);
489   }
490
491
492   pipe_surface_reference(&dst_surf, NULL);
493   return TRUE;
494}
495
496void xorg_composite(struct exa_context *exa,
497                    struct exa_pixmap_priv *dst,
498                    int srcX, int srcY, int maskX, int maskY,
499                    int dstX, int dstY, int width, int height)
500{
501   if (exa->num_bound_samplers == 0 ) { /* solid fill */
502      renderer_solid(exa->renderer,
503                     dstX, dstY, dstX + width, dstY + height,
504                     exa->solid_color);
505   } else {
506      int pos[6] = {srcX, srcY, maskX, maskY, dstX, dstY};
507      float *src_matrix = NULL;
508      float *mask_matrix = NULL;
509
510      if (exa->transform.has_src)
511         src_matrix = exa->transform.src;
512      if (exa->transform.has_mask)
513         mask_matrix = exa->transform.mask;
514
515      renderer_texture(exa->renderer,
516                       pos, width, height,
517                       exa->bound_textures,
518                       exa->num_bound_samplers,
519                       src_matrix, mask_matrix);
520   }
521}
522
523boolean xorg_solid_bind_state(struct exa_context *exa,
524                              struct exa_pixmap_priv *pixmap,
525                              Pixel fg)
526{
527   struct pipe_surface *dst_surf = xorg_gpu_surface(exa->scrn, pixmap);
528   unsigned vs_traits, fs_traits;
529   struct xorg_shader shader;
530
531   pixel_to_float4(fg, exa->solid_color);
532   exa->has_solid_color = TRUE;
533
534#if 0
535   debug_printf("Color Pixel=(%d, %d, %d, %d), RGBA=(%f, %f, %f, %f)\n",
536                (fg >> 24) & 0xff, (fg >> 16) & 0xff,
537                (fg >> 8) & 0xff,  (fg >> 0) & 0xff,
538                exa->solid_color[0], exa->solid_color[1],
539                exa->solid_color[2], exa->solid_color[3]);
540#endif
541
542   vs_traits = VS_SOLID_FILL;
543   fs_traits = FS_SOLID_FILL;
544
545   renderer_bind_destination(exa->renderer, dst_surf,
546                             pixmap->width, pixmap->height);
547   bind_blend_state(exa, PictOpSrc, NULL, NULL, NULL);
548   cso_set_samplers(exa->renderer->cso, 0, NULL);
549   cso_set_sampler_textures(exa->renderer->cso, 0, NULL);
550
551   shader = xorg_shaders_get(exa->renderer->shaders, vs_traits, fs_traits);
552   cso_set_vertex_shader_handle(exa->renderer->cso, shader.vs);
553   cso_set_fragment_shader_handle(exa->renderer->cso, shader.fs);
554
555   renderer_begin_solid(exa->renderer);
556
557   pipe_surface_reference(&dst_surf, NULL);
558   return TRUE;
559}
560
561void xorg_solid(struct exa_context *exa,
562                struct exa_pixmap_priv *pixmap,
563                int x0, int y0, int x1, int y1)
564{
565   renderer_solid(exa->renderer,
566                  x0, y0, x1, y1, exa->solid_color);
567}
568
569void
570xorg_composite_done(struct exa_context *exa)
571{
572   renderer_draw_flush(exa->renderer);
573
574   exa->transform.has_src = FALSE;
575   exa->transform.has_mask = FALSE;
576   exa->has_solid_color = FALSE;
577   exa->num_bound_samplers = 0;
578}
579