xorg_composite.c revision cb060f3b987c9fa07ebe06cf2e7e54d1eaded1e1
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   default:
155      debug_printf("Unkown xrender filter");
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.blend_enable = 1;
221   blend.colormask |= PIPE_MASK_RGBA;
222
223   blend.rgb_src_factor   = blend_opt.rgb_src;
224   blend.alpha_src_factor = blend_opt.rgb_src;
225   blend.rgb_dst_factor   = blend_opt.rgb_dst;
226   blend.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{
234   boolean set_alpha = FALSE;
235   boolean swizzle = FALSE;
236   unsigned ret = 0;
237
238   if (pSrc->picture_format == pSrcPicture->format) {
239      if (pSrc->picture_format == PICT_a8)
240         return mask ? FS_MASK_LUMINANCE : FS_MASK_LUMINANCE;
241      return 0;
242   }
243
244   if (pSrc->picture_format != PICT_a8r8g8b8) {
245      assert(!"can not handle formats");
246      return 0;
247   }
248
249   /* pSrc->picture_format == PICT_a8r8g8b8 */
250   switch (pSrcPicture->format) {
251   case PICT_x8b8g8r8:
252   case PICT_b8g8r8:
253      set_alpha = TRUE; /* fall trough */
254   case PICT_a8b8g8r8:
255      swizzle = TRUE;
256      break;
257   case PICT_x8r8g8b8:
258   case PICT_r8g8b8:
259      set_alpha = TRUE; /* fall through */
260   case PICT_a8r8g8b8:
261      break;
262#ifdef PICT_TYPE_BGRA
263   case PICT_b8g8r8a8:
264   case PICT_b8g8r8x8:
265   case PICT_a2r10g10b10:
266   case PICT_x2r10g10b10:
267   case PICT_a2b10g10r10:
268   case PICT_x2b10g10r10:
269#endif
270   default:
271      assert(!"can not handle formats");
272      return 0;
273   }
274
275   if (set_alpha)
276      ret |= mask ? FS_MASK_SET_ALPHA : FS_SRC_SET_ALPHA;
277   if (swizzle)
278      ret |= mask ? FS_MASK_SWIZZLE_RGB : FS_SRC_SWIZZLE_RGB;
279
280   return ret;
281}
282
283static void
284bind_shaders(struct exa_context *exa, int op,
285             PicturePtr pSrcPicture, PicturePtr pMaskPicture,
286             struct exa_pixmap_priv *pSrc, struct exa_pixmap_priv *pMask)
287{
288   unsigned vs_traits = 0, fs_traits = 0;
289   struct xorg_shader shader;
290
291   exa->has_solid_color = FALSE;
292
293   if (pSrcPicture) {
294      if (pSrcPicture->repeatType == RepeatNone && pSrcPicture->transform)
295         fs_traits |= FS_SRC_REPEAT_NONE;
296
297      if (pSrcPicture->pSourcePict) {
298         if (pSrcPicture->pSourcePict->type == SourcePictTypeSolidFill) {
299            fs_traits |= FS_SOLID_FILL;
300            vs_traits |= VS_SOLID_FILL;
301            debug_assert(pSrcPicture->format == PICT_a8r8g8b8);
302            pixel_to_float4(pSrcPicture->pSourcePict->solidFill.color,
303                            exa->solid_color);
304            exa->has_solid_color = TRUE;
305         } else {
306            debug_assert("!gradients not supported");
307         }
308      } else {
309         fs_traits |= FS_COMPOSITE;
310         vs_traits |= VS_COMPOSITE;
311      }
312
313      fs_traits |= picture_format_fixups(pSrc, pSrcPicture, FALSE);
314   }
315
316   if (pMaskPicture) {
317      vs_traits |= VS_MASK;
318      fs_traits |= FS_MASK;
319      if (pMaskPicture->repeatType == RepeatNone && pMaskPicture->transform)
320         fs_traits |= FS_MASK_REPEAT_NONE;
321      if (pMaskPicture->componentAlpha) {
322         struct xorg_composite_blend blend;
323         blend_for_op(&blend, op,
324                      pSrcPicture, pMaskPicture, NULL);
325         if (blend.alpha_src) {
326            fs_traits |= FS_CA_SRCALPHA;
327         } else
328            fs_traits |= FS_CA_FULL;
329      }
330
331      fs_traits |= picture_format_fixups(pMask, pMaskPicture, TRUE);
332   }
333
334   shader = xorg_shaders_get(exa->renderer->shaders, vs_traits, fs_traits);
335   cso_set_vertex_shader_handle(exa->renderer->cso, shader.vs);
336   cso_set_fragment_shader_handle(exa->renderer->cso, shader.fs);
337}
338
339static void
340bind_samplers(struct exa_context *exa, int op,
341              PicturePtr pSrcPicture, PicturePtr pMaskPicture,
342              PicturePtr pDstPicture,
343              struct exa_pixmap_priv *pSrc,
344              struct exa_pixmap_priv *pMask,
345              struct exa_pixmap_priv *pDst)
346{
347   struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS];
348   struct pipe_sampler_state src_sampler, mask_sampler;
349
350   exa->num_bound_samplers = 0;
351
352#if 0
353   if ((pSrc && (exa->pipe->is_texture_referenced(exa->pipe, pSrc->tex, 0, 0) &
354                 PIPE_REFERENCED_FOR_WRITE)) ||
355       (pMask && (exa->pipe->is_texture_referenced(exa->pipe, pMask->tex, 0, 0) &
356        PIPE_REFERENCED_FOR_WRITE)))
357      xorg_exa_flush(exa, PIPE_FLUSH_RENDER_CACHE, NULL);
358#endif
359
360   memset(&src_sampler, 0, sizeof(struct pipe_sampler_state));
361   memset(&mask_sampler, 0, sizeof(struct pipe_sampler_state));
362
363   if (pSrcPicture && pSrc) {
364      if (exa->has_solid_color) {
365         debug_assert(!"solid color with textures");
366         samplers[0] = NULL;
367         exa->bound_textures[0] = NULL;
368      } else {
369         unsigned src_wrap = render_repeat_to_gallium(
370            pSrcPicture->repeatType);
371         int filter;
372
373         render_filter_to_gallium(pSrcPicture->filter, &filter);
374
375         src_sampler.wrap_s = src_wrap;
376         src_sampler.wrap_t = src_wrap;
377         src_sampler.min_img_filter = filter;
378         src_sampler.mag_img_filter = filter;
379         src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST;
380         src_sampler.normalized_coords = 1;
381         samplers[0] = &src_sampler;
382         exa->bound_textures[0] = pSrc->tex;
383         exa->num_bound_samplers = 1;
384      }
385   }
386
387   if (pMaskPicture && pMask) {
388      unsigned mask_wrap = render_repeat_to_gallium(
389         pMaskPicture->repeatType);
390      int filter;
391
392      render_filter_to_gallium(pMaskPicture->filter, &filter);
393
394      mask_sampler.wrap_s = mask_wrap;
395      mask_sampler.wrap_t = mask_wrap;
396      mask_sampler.min_img_filter = filter;
397      mask_sampler.mag_img_filter = filter;
398      src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST;
399      mask_sampler.normalized_coords = 1;
400      samplers[1] = &mask_sampler;
401      exa->bound_textures[1] = pMask->tex;
402      exa->num_bound_samplers = 2;
403   }
404
405   cso_set_samplers(exa->renderer->cso, exa->num_bound_samplers,
406                    (const struct pipe_sampler_state **)samplers);
407   cso_set_sampler_textures(exa->renderer->cso, exa->num_bound_samplers,
408                            exa->bound_textures);
409}
410
411static void
412setup_vs_constant_buffer(struct exa_context *exa,
413                         int width, int height)
414{
415   const int param_bytes = 8 * sizeof(float);
416   float vs_consts[8] = {
417      2.f/width, 2.f/height, 1, 1,
418      -1, -1, 0, 0
419   };
420   renderer_set_constants(exa->renderer, PIPE_SHADER_VERTEX,
421                          vs_consts, param_bytes);
422}
423
424
425static void
426setup_fs_constant_buffer(struct exa_context *exa)
427{
428   const int param_bytes = 4 * sizeof(float);
429   const float fs_consts[8] = {
430      0, 0, 0, 1,
431   };
432   renderer_set_constants(exa->renderer, PIPE_SHADER_FRAGMENT,
433                          fs_consts, param_bytes);
434}
435
436static void
437setup_constant_buffers(struct exa_context *exa, struct exa_pixmap_priv *pDst)
438{
439   int width = pDst->tex->width[0];
440   int height = pDst->tex->height[0];
441
442   setup_vs_constant_buffer(exa, width, height);
443   setup_fs_constant_buffer(exa);
444}
445
446static INLINE boolean matrix_from_pict_transform(PictTransform *trans, float *matrix)
447{
448   if (!trans)
449      return FALSE;
450
451   matrix[0] = XFixedToDouble(trans->matrix[0][0]);
452   matrix[3] = XFixedToDouble(trans->matrix[0][1]);
453   matrix[6] = XFixedToDouble(trans->matrix[0][2]);
454
455   matrix[1] = XFixedToDouble(trans->matrix[1][0]);
456   matrix[4] = XFixedToDouble(trans->matrix[1][1]);
457   matrix[7] = XFixedToDouble(trans->matrix[1][2]);
458
459   matrix[2] = XFixedToDouble(trans->matrix[2][0]);
460   matrix[5] = XFixedToDouble(trans->matrix[2][1]);
461   matrix[8] = XFixedToDouble(trans->matrix[2][2]);
462
463   return TRUE;
464}
465
466static void
467setup_transforms(struct  exa_context *exa,
468                 PicturePtr pSrcPicture, PicturePtr pMaskPicture)
469{
470   PictTransform *src_t = NULL;
471   PictTransform *mask_t = NULL;
472
473   if (pSrcPicture)
474      src_t = pSrcPicture->transform;
475   if (pMaskPicture)
476      mask_t = pMaskPicture->transform;
477
478   exa->transform.has_src  =
479      matrix_from_pict_transform(src_t, exa->transform.src);
480   exa->transform.has_mask =
481      matrix_from_pict_transform(mask_t, exa->transform.mask);
482}
483
484boolean xorg_composite_bind_state(struct exa_context *exa,
485                                  int op,
486                                  PicturePtr pSrcPicture,
487                                  PicturePtr pMaskPicture,
488                                  PicturePtr pDstPicture,
489                                  struct exa_pixmap_priv *pSrc,
490                                  struct exa_pixmap_priv *pMask,
491                                  struct exa_pixmap_priv *pDst)
492{
493   renderer_bind_framebuffer(exa->renderer, pDst);
494   renderer_bind_viewport(exa->renderer, pDst);
495   bind_blend_state(exa, op, pSrcPicture, pMaskPicture, pDstPicture);
496   renderer_bind_rasterizer(exa->renderer);
497   bind_shaders(exa, op, pSrcPicture, pMaskPicture, pSrc, pMask);
498   bind_samplers(exa, op, pSrcPicture, pMaskPicture,
499                 pDstPicture, pSrc, pMask, pDst);
500   setup_constant_buffers(exa, pDst);
501
502   setup_transforms(exa, pSrcPicture, pMaskPicture);
503
504   if (exa->num_bound_samplers == 0 ) { /* solid fill */
505      renderer_begin_solid(exa->renderer);
506   } else {
507      renderer_begin_textures(exa->renderer,
508                              exa->bound_textures,
509                              exa->num_bound_samplers);
510   }
511
512   return TRUE;
513}
514
515void xorg_composite(struct exa_context *exa,
516                    struct exa_pixmap_priv *dst,
517                    int srcX, int srcY, int maskX, int maskY,
518                    int dstX, int dstY, int width, int height)
519{
520   if (exa->num_bound_samplers == 0 ) { /* solid fill */
521      renderer_solid(exa->renderer,
522                     dstX, dstY, dstX + width, dstY + height,
523                     exa->solid_color);
524   } else {
525      int pos[6] = {srcX, srcY, maskX, maskY, dstX, dstY};
526      float *src_matrix = NULL;
527      float *mask_matrix = NULL;
528
529      if (exa->transform.has_src)
530         src_matrix = exa->transform.src;
531      if (exa->transform.has_mask)
532         mask_matrix = exa->transform.mask;
533
534      renderer_texture(exa->renderer,
535                       pos, width, height,
536                       exa->bound_textures,
537                       exa->num_bound_samplers,
538                       src_matrix, mask_matrix);
539   }
540}
541
542boolean xorg_solid_bind_state(struct exa_context *exa,
543                              struct exa_pixmap_priv *pixmap,
544                              Pixel fg)
545{
546   unsigned vs_traits, fs_traits;
547   struct xorg_shader shader;
548
549   pixel_to_float4(fg, exa->solid_color);
550   exa->has_solid_color = TRUE;
551
552#if 0
553   debug_printf("Color Pixel=(%d, %d, %d, %d), RGBA=(%f, %f, %f, %f)\n",
554                (fg >> 24) & 0xff, (fg >> 16) & 0xff,
555                (fg >> 8) & 0xff,  (fg >> 0) & 0xff,
556                exa->solid_color[0], exa->solid_color[1],
557                exa->solid_color[2], exa->solid_color[3]);
558#endif
559
560   vs_traits = VS_SOLID_FILL;
561   fs_traits = FS_SOLID_FILL;
562
563   renderer_bind_framebuffer(exa->renderer, pixmap);
564   renderer_bind_viewport(exa->renderer, pixmap);
565   renderer_bind_rasterizer(exa->renderer);
566   bind_blend_state(exa, PictOpSrc, NULL, NULL, NULL);
567   setup_constant_buffers(exa, pixmap);
568
569   shader = xorg_shaders_get(exa->renderer->shaders, vs_traits, fs_traits);
570   cso_set_vertex_shader_handle(exa->renderer->cso, shader.vs);
571   cso_set_fragment_shader_handle(exa->renderer->cso, shader.fs);
572
573   renderer_begin_solid(exa->renderer);
574
575   return TRUE;
576}
577
578void xorg_solid(struct exa_context *exa,
579                struct exa_pixmap_priv *pixmap,
580                int x0, int y0, int x1, int y1)
581{
582   renderer_solid(exa->renderer,
583                  x0, y0, x1, y1, exa->solid_color);
584}
585
586