xorg_composite.c revision a6d527d7b82579feae9db20657d47a3f86115bb4
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;
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      return TRUE;
203   }
204   XORG_FALLBACK("Unsupported composition operation = %d", op);
205}
206
207static void
208bind_blend_state(struct exa_context *exa, int op,
209                 PicturePtr pSrcPicture,
210                 PicturePtr pMaskPicture,
211                 PicturePtr pDstPicture)
212{
213   struct xorg_composite_blend blend_opt;
214   struct pipe_blend_state blend;
215
216   blend_for_op(&blend_opt, op, pSrcPicture, pMaskPicture, pDstPicture);
217
218   memset(&blend, 0, sizeof(struct pipe_blend_state));
219   blend.blend_enable = 1;
220   blend.colormask |= PIPE_MASK_RGBA;
221
222   blend.rgb_src_factor   = blend_opt.rgb_src;
223   blend.alpha_src_factor = blend_opt.rgb_src;
224   blend.rgb_dst_factor   = blend_opt.rgb_dst;
225   blend.alpha_dst_factor = blend_opt.rgb_dst;
226
227   cso_set_blend(exa->renderer->cso, &blend);
228}
229
230
231static void
232bind_shaders(struct exa_context *exa, int op,
233             PicturePtr pSrcPicture, PicturePtr pMaskPicture)
234{
235   unsigned vs_traits = 0, fs_traits = 0;
236   struct xorg_shader shader;
237
238   exa->has_solid_color = FALSE;
239
240   if (pSrcPicture) {
241      if (pSrcPicture->pSourcePict) {
242         if (pSrcPicture->pSourcePict->type == SourcePictTypeSolidFill) {
243            fs_traits |= FS_SOLID_FILL;
244            vs_traits |= VS_SOLID_FILL;
245            debug_assert(pSrcPicture->format == PICT_a8r8g8b8);
246            pixel_to_float4(pSrcPicture->pSourcePict->solidFill.color,
247                            exa->solid_color);
248            exa->has_solid_color = TRUE;
249         } else {
250            debug_assert("!gradients not supported");
251         }
252      } else {
253         fs_traits |= FS_COMPOSITE;
254         vs_traits |= VS_COMPOSITE;
255      }
256   }
257
258   if (pMaskPicture) {
259      vs_traits |= VS_MASK;
260      fs_traits |= FS_MASK;
261      if (pMaskPicture->componentAlpha) {
262         struct xorg_composite_blend blend;
263         blend_for_op(&blend, op,
264                      pSrcPicture, pMaskPicture, NULL);
265         if (blend.alpha_src) {
266            fs_traits |= FS_CA_SRCALPHA;
267         } else
268            fs_traits |= FS_CA_FULL;
269      }
270   }
271
272   shader = xorg_shaders_get(exa->renderer->shaders, vs_traits, fs_traits);
273   cso_set_vertex_shader_handle(exa->renderer->cso, shader.vs);
274   cso_set_fragment_shader_handle(exa->renderer->cso, shader.fs);
275}
276
277static void
278bind_samplers(struct exa_context *exa, int op,
279              PicturePtr pSrcPicture, PicturePtr pMaskPicture,
280              PicturePtr pDstPicture,
281              struct exa_pixmap_priv *pSrc,
282              struct exa_pixmap_priv *pMask,
283              struct exa_pixmap_priv *pDst)
284{
285   struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS];
286   struct pipe_sampler_state src_sampler, mask_sampler;
287
288   exa->num_bound_samplers = 0;
289
290#if 0
291   if ((pSrc && (exa->pipe->is_texture_referenced(exa->pipe, pSrc->tex, 0, 0) &
292                 PIPE_REFERENCED_FOR_WRITE)) ||
293       (pMask && (exa->pipe->is_texture_referenced(exa->pipe, pMask->tex, 0, 0) &
294        PIPE_REFERENCED_FOR_WRITE)))
295      xorg_exa_flush(exa, PIPE_FLUSH_RENDER_CACHE, NULL);
296#endif
297
298   memset(&src_sampler, 0, sizeof(struct pipe_sampler_state));
299   memset(&mask_sampler, 0, sizeof(struct pipe_sampler_state));
300
301   if (pSrcPicture && pSrc) {
302      if (exa->has_solid_color) {
303         debug_assert(!"solid color with textures");
304         samplers[0] = NULL;
305         exa->bound_textures[0] = NULL;
306      } else {
307         unsigned src_wrap = render_repeat_to_gallium(
308            pSrcPicture->repeatType);
309         int filter;
310
311         render_filter_to_gallium(pSrcPicture->filter, &filter);
312
313         src_sampler.wrap_s = src_wrap;
314         src_sampler.wrap_t = src_wrap;
315         src_sampler.min_img_filter = filter;
316         src_sampler.mag_img_filter = filter;
317         src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST;
318         src_sampler.normalized_coords = 1;
319         samplers[0] = &src_sampler;
320         exa->bound_textures[0] = pSrc->tex;
321         exa->num_bound_samplers = 1;
322      }
323   }
324
325   if (pMaskPicture && pMask) {
326      unsigned mask_wrap = render_repeat_to_gallium(
327         pMaskPicture->repeatType);
328      int filter;
329
330      render_filter_to_gallium(pMaskPicture->filter, &filter);
331
332      mask_sampler.wrap_s = mask_wrap;
333      mask_sampler.wrap_t = mask_wrap;
334      mask_sampler.min_img_filter = filter;
335      mask_sampler.mag_img_filter = filter;
336      src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST;
337      mask_sampler.normalized_coords = 1;
338      samplers[1] = &mask_sampler;
339      exa->bound_textures[1] = pMask->tex;
340      exa->num_bound_samplers = 2;
341   }
342
343   cso_set_samplers(exa->renderer->cso, exa->num_bound_samplers,
344                    (const struct pipe_sampler_state **)samplers);
345   cso_set_sampler_textures(exa->renderer->cso, exa->num_bound_samplers,
346                            exa->bound_textures);
347}
348
349static void
350setup_vs_constant_buffer(struct exa_context *exa,
351                         int width, int height)
352{
353   const int param_bytes = 8 * sizeof(float);
354   float vs_consts[8] = {
355      2.f/width, 2.f/height, 1, 1,
356      -1, -1, 0, 0
357   };
358   renderer_set_constants(exa->renderer, PIPE_SHADER_VERTEX,
359                          vs_consts, param_bytes);
360}
361
362
363static void
364setup_fs_constant_buffer(struct exa_context *exa)
365{
366   const int param_bytes = 4 * sizeof(float);
367   const float fs_consts[8] = {
368      0, 0, 0, 1,
369   };
370   renderer_set_constants(exa->renderer, PIPE_SHADER_FRAGMENT,
371                          fs_consts, param_bytes);
372}
373
374static void
375setup_constant_buffers(struct exa_context *exa, struct exa_pixmap_priv *pDst)
376{
377   int width = pDst->tex->width[0];
378   int height = pDst->tex->height[0];
379
380   setup_vs_constant_buffer(exa, width, height);
381   setup_fs_constant_buffer(exa);
382}
383
384static INLINE boolean matrix_from_pict_transform(PictTransform *trans, float *matrix)
385{
386   if (!trans)
387      return FALSE;
388
389   matrix[0] = XFixedToDouble(trans->matrix[0][0]);
390   matrix[3] = XFixedToDouble(trans->matrix[0][1]);
391   matrix[6] = XFixedToDouble(trans->matrix[0][2]);
392
393   matrix[1] = XFixedToDouble(trans->matrix[1][0]);
394   matrix[4] = XFixedToDouble(trans->matrix[1][1]);
395   matrix[7] = XFixedToDouble(trans->matrix[1][2]);
396
397   matrix[2] = XFixedToDouble(trans->matrix[2][0]);
398   matrix[5] = XFixedToDouble(trans->matrix[2][1]);
399   matrix[8] = XFixedToDouble(trans->matrix[2][2]);
400
401   return TRUE;
402}
403
404static void
405setup_transforms(struct  exa_context *exa,
406                 PicturePtr pSrcPicture, PicturePtr pMaskPicture)
407{
408   PictTransform *src_t = NULL;
409   PictTransform *mask_t = NULL;
410
411   if (pSrcPicture)
412      src_t = pSrcPicture->transform;
413   if (pMaskPicture)
414      mask_t = pMaskPicture->transform;
415
416   exa->transform.has_src  =
417      matrix_from_pict_transform(src_t, exa->transform.src);
418   exa->transform.has_mask =
419      matrix_from_pict_transform(mask_t, exa->transform.mask);
420}
421
422boolean xorg_composite_bind_state(struct exa_context *exa,
423                                  int op,
424                                  PicturePtr pSrcPicture,
425                                  PicturePtr pMaskPicture,
426                                  PicturePtr pDstPicture,
427                                  struct exa_pixmap_priv *pSrc,
428                                  struct exa_pixmap_priv *pMask,
429                                  struct exa_pixmap_priv *pDst)
430{
431   renderer_bind_framebuffer(exa->renderer, pDst);
432   renderer_bind_viewport(exa->renderer, pDst);
433   bind_blend_state(exa, op, pSrcPicture, pMaskPicture, pDstPicture);
434   renderer_bind_rasterizer(exa->renderer);
435   bind_shaders(exa, op, pSrcPicture, pMaskPicture);
436   bind_samplers(exa, op, pSrcPicture, pMaskPicture,
437                 pDstPicture, pSrc, pMask, pDst);
438   setup_constant_buffers(exa, pDst);
439
440   setup_transforms(exa, pSrcPicture, pMaskPicture);
441
442   if (exa->num_bound_samplers == 0 ) { /* solid fill */
443      renderer_begin_solid(exa->renderer);
444   } else {
445      renderer_begin_textures(exa->renderer,
446                              exa->bound_textures,
447                              exa->num_bound_samplers);
448   }
449
450   return TRUE;
451}
452
453void xorg_composite(struct exa_context *exa,
454                    struct exa_pixmap_priv *dst,
455                    int srcX, int srcY, int maskX, int maskY,
456                    int dstX, int dstY, int width, int height)
457{
458   if (exa->num_bound_samplers == 0 ) { /* solid fill */
459      renderer_solid(exa->renderer,
460                     dstX, dstY, dstX + width, dstY + height,
461                     exa->solid_color);
462   } else {
463      int pos[6] = {srcX, srcY, maskX, maskY, dstX, dstY};
464      float *src_matrix = NULL;
465      float *mask_matrix = NULL;
466
467      if (exa->transform.has_src)
468         src_matrix = exa->transform.src;
469      if (exa->transform.has_mask)
470         mask_matrix = exa->transform.mask;
471
472#if 0
473      renderer_draw_textures(exa->renderer,
474                             pos, width, height,
475                             exa->bound_textures,
476                             exa->num_bound_samplers,
477                             src_matrix, mask_matrix);
478#else
479      renderer_texture(exa->renderer,
480                       pos, width, height,
481                       exa->bound_textures,
482                       exa->num_bound_samplers,
483                       src_matrix, mask_matrix);
484#endif
485   }
486}
487
488boolean xorg_solid_bind_state(struct exa_context *exa,
489                              struct exa_pixmap_priv *pixmap,
490                              Pixel fg)
491{
492   unsigned vs_traits, fs_traits;
493   struct xorg_shader shader;
494
495   pixel_to_float4(fg, exa->solid_color);
496   exa->has_solid_color = TRUE;
497
498#if 0
499   debug_printf("Color Pixel=(%d, %d, %d, %d), RGBA=(%f, %f, %f, %f)\n",
500                (fg >> 24) & 0xff, (fg >> 16) & 0xff,
501                (fg >> 8) & 0xff,  (fg >> 0) & 0xff,
502                exa->solid_color[0], exa->solid_color[1],
503                exa->solid_color[2], exa->solid_color[3]);
504#endif
505
506   vs_traits = VS_SOLID_FILL;
507   fs_traits = FS_SOLID_FILL;
508
509   renderer_bind_framebuffer(exa->renderer, pixmap);
510   renderer_bind_viewport(exa->renderer, pixmap);
511   renderer_bind_rasterizer(exa->renderer);
512   bind_blend_state(exa, PictOpSrc, NULL, NULL, NULL);
513   setup_constant_buffers(exa, pixmap);
514
515   shader = xorg_shaders_get(exa->renderer->shaders, vs_traits, fs_traits);
516   cso_set_vertex_shader_handle(exa->renderer->cso, shader.vs);
517   cso_set_fragment_shader_handle(exa->renderer->cso, shader.fs);
518
519   renderer_begin_solid(exa->renderer);
520
521   return TRUE;
522}
523
524void xorg_solid(struct exa_context *exa,
525                struct exa_pixmap_priv *pixmap,
526                int x0, int y0, int x1, int y1)
527{
528   renderer_solid(exa->renderer,
529                  x0, y0, x1, y1, exa->solid_color);
530}
531
532