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