xorg_composite.c revision 074e069910c7082620be4211fe5496365f828886
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
12struct xorg_composite_blend {
13   int op:8;
14
15   unsigned rgb_src_factor:5;    /**< PIPE_BLENDFACTOR_x */
16   unsigned alpha_src_factor:5;  /**< PIPE_BLENDFACTOR_x */
17
18   unsigned rgb_dst_factor:5;    /**< PIPE_BLENDFACTOR_x */
19   unsigned alpha_dst_factor:5;  /**< PIPE_BLENDFACTOR_x */
20};
21
22#define BLEND_OP_OVER 3
23static const struct xorg_composite_blend xorg_blends[] = {
24   { PictOpClear,
25     PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO,
26     PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO },
27
28   { PictOpSrc,
29     PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ONE,
30     PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO },
31
32   { PictOpDst,
33     PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO,
34     PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ONE },
35
36   { PictOpOver,
37     PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ONE,
38     PIPE_BLENDFACTOR_INV_SRC_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA },
39
40   { PictOpOverReverse,
41     PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_ONE,
42     PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_INV_SRC_ALPHA },
43
44   { PictOpIn,
45     PIPE_BLENDFACTOR_DST_ALPHA, PIPE_BLENDFACTOR_ONE,
46     PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_INV_SRC_ALPHA },
47
48   { PictOpInReverse,
49     PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ONE,
50     PIPE_BLENDFACTOR_SRC_ALPHA, PIPE_BLENDFACTOR_ONE },
51
52   { PictOpOut,
53     PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_ONE,
54     PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_INV_SRC_ALPHA },
55
56   { PictOpOutReverse,
57     PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ONE,
58     PIPE_BLENDFACTOR_INV_SRC_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA },
59
60   { PictOpAtop,
61     PIPE_BLENDFACTOR_DST_ALPHA, PIPE_BLENDFACTOR_ONE,
62     PIPE_BLENDFACTOR_INV_SRC_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA },
63
64   { PictOpAtopReverse,
65     PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_ONE,
66     PIPE_BLENDFACTOR_SRC_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA },
67
68   { PictOpXor,
69     PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_ONE,
70     PIPE_BLENDFACTOR_INV_SRC_ALPHA, PIPE_BLENDFACTOR_ONE },
71
72   { PictOpAdd,
73     PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ONE,
74     PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ONE },
75};
76
77
78static INLINE void
79pixel_to_float4(Pixel pixel, float *color)
80{
81   CARD32	    r, g, b, a;
82
83   a = (pixel >> 24) & 0xff;
84   r = (pixel >> 16) & 0xff;
85   g = (pixel >>  8) & 0xff;
86   b = (pixel >>  0) & 0xff;
87   color[0] = ((float)r) / 255.;
88   color[1] = ((float)g) / 255.;
89   color[2] = ((float)b) / 255.;
90   color[3] = ((float)a) / 255.;
91}
92
93struct acceleration_info {
94   int op : 16;
95   int with_mask : 1;
96   int component_alpha : 1;
97};
98static const struct acceleration_info accelerated_ops[] = {
99   {PictOpClear,       1, 0},
100   {PictOpSrc,         1, 0},
101   {PictOpDst,         1, 0},
102   {PictOpOver,        1, 0},
103   {PictOpOverReverse, 1, 0},
104   {PictOpIn,          1, 0},
105   {PictOpInReverse,   1, 0},
106   {PictOpOut,         1, 0},
107   {PictOpOutReverse,  1, 0},
108   {PictOpAtop,        1, 0},
109   {PictOpAtopReverse, 1, 0},
110   {PictOpXor,         1, 0},
111   {PictOpAdd,         1, 0},
112   {PictOpSaturate,    1, 0},
113};
114
115static struct xorg_composite_blend
116blend_for_op(int op)
117{
118   const int num_blends =
119      sizeof(xorg_blends)/sizeof(struct xorg_composite_blend);
120   int i;
121
122   for (i = 0; i < num_blends; ++i) {
123      if (xorg_blends[i].op == op)
124         return xorg_blends[i];
125   }
126   return xorg_blends[BLEND_OP_OVER];
127}
128
129static INLINE int
130render_repeat_to_gallium(int mode)
131{
132   switch(mode) {
133   case RepeatNone:
134      return PIPE_TEX_WRAP_CLAMP;
135   case RepeatNormal:
136      return PIPE_TEX_WRAP_REPEAT;
137   case RepeatReflect:
138      return PIPE_TEX_WRAP_MIRROR_REPEAT;
139   case RepeatPad:
140      return PIPE_TEX_WRAP_CLAMP_TO_EDGE;
141   default:
142      debug_printf("Unsupported repeat mode\n");
143   }
144   return PIPE_TEX_WRAP_REPEAT;
145}
146
147boolean xorg_composite_accelerated(int op,
148                                   PicturePtr pSrcPicture,
149                                   PicturePtr pMaskPicture,
150                                   PicturePtr pDstPicture)
151{
152   ScreenPtr pScreen = pDstPicture->pDrawable->pScreen;
153   ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
154   modesettingPtr ms = modesettingPTR(pScrn);
155   unsigned i;
156   unsigned accel_ops_count =
157      sizeof(accelerated_ops)/sizeof(struct acceleration_info);
158
159   if (pSrcPicture->pSourcePict) {
160      if (pSrcPicture->pSourcePict->type != SourcePictTypeSolidFill)
161         XORG_FALLBACK("gradients not enabled (haven't been well tested)");
162   }
163
164   for (i = 0; i < accel_ops_count; ++i) {
165      if (op == accelerated_ops[i].op) {
166         /* Check for unsupported component alpha */
167         if ((pSrcPicture->componentAlpha &&
168              !accelerated_ops[i].component_alpha) ||
169             (pMaskPicture &&
170              (!accelerated_ops[i].with_mask ||
171               (pMaskPicture->componentAlpha &&
172                !accelerated_ops[i].component_alpha))))
173            XORG_FALLBACK("component alpha unsupported (PictOpOver=%s(%d)",
174                          (accelerated_ops[i].op == PictOpOver) ? "yes" : "no",
175                          accelerated_ops[i].op);
176         return TRUE;
177      }
178   }
179   XORG_FALLBACK("unsupported operation");
180}
181
182static void
183bind_blend_state(struct exa_context *exa, int op,
184                 PicturePtr pSrcPicture, PicturePtr pMaskPicture)
185{
186   struct xorg_composite_blend blend_opt;
187   struct pipe_blend_state blend;
188
189   blend_opt = blend_for_op(op);
190
191   memset(&blend, 0, sizeof(struct pipe_blend_state));
192   blend.blend_enable = 1;
193   blend.colormask |= PIPE_MASK_RGBA;
194
195   blend.rgb_src_factor   = blend_opt.rgb_src_factor;
196   blend.alpha_src_factor = blend_opt.alpha_src_factor;
197   blend.rgb_dst_factor   = blend_opt.rgb_dst_factor;
198   blend.alpha_dst_factor = blend_opt.alpha_dst_factor;
199
200   cso_set_blend(exa->renderer->cso, &blend);
201}
202
203
204static void
205bind_shaders(struct exa_context *exa, int op,
206             PicturePtr pSrcPicture, PicturePtr pMaskPicture)
207{
208   unsigned vs_traits = 0, fs_traits = 0;
209   struct xorg_shader shader;
210
211   exa->has_solid_color = FALSE;
212
213   if (pSrcPicture) {
214      if (pSrcPicture->pSourcePict) {
215         if (pSrcPicture->pSourcePict->type == SourcePictTypeSolidFill) {
216            fs_traits |= FS_SOLID_FILL;
217            vs_traits |= VS_SOLID_FILL;
218            debug_assert(pSrcPicture->format == PICT_a8r8g8b8);
219            pixel_to_float4(pSrcPicture->pSourcePict->solidFill.color,
220                            exa->solid_color);
221            exa->has_solid_color = TRUE;
222         } else {
223            debug_assert("!gradients not supported");
224         }
225      } else {
226         fs_traits |= FS_COMPOSITE;
227         vs_traits |= VS_COMPOSITE;
228      }
229   }
230
231   if (pMaskPicture) {
232      vs_traits |= VS_MASK;
233      fs_traits |= FS_MASK;
234   }
235
236   shader = xorg_shaders_get(exa->renderer->shaders, vs_traits, fs_traits);
237   cso_set_vertex_shader_handle(exa->renderer->cso, shader.vs);
238   cso_set_fragment_shader_handle(exa->renderer->cso, shader.fs);
239}
240
241
242static void
243bind_samplers(struct exa_context *exa, int op,
244              PicturePtr pSrcPicture, PicturePtr pMaskPicture,
245              PicturePtr pDstPicture,
246              struct exa_pixmap_priv *pSrc,
247              struct exa_pixmap_priv *pMask,
248              struct exa_pixmap_priv *pDst)
249{
250   struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS];
251   struct pipe_sampler_state src_sampler, mask_sampler;
252
253   exa->num_bound_samplers = 0;
254
255   memset(&src_sampler, 0, sizeof(struct pipe_sampler_state));
256   memset(&mask_sampler, 0, sizeof(struct pipe_sampler_state));
257
258   if ((pSrc && exa->pipe->is_texture_referenced(exa->pipe, pSrc->tex, 0, 0) &
259        PIPE_REFERENCED_FOR_WRITE) ||
260       (pMask && exa->pipe->is_texture_referenced(exa->pipe, pMask->tex, 0, 0) &
261        PIPE_REFERENCED_FOR_WRITE))
262      exa->pipe->flush(exa->pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
263
264   if (pSrcPicture && pSrc) {
265      unsigned src_wrap = render_repeat_to_gallium(
266         pSrcPicture->repeatType);
267      src_sampler.wrap_s = src_wrap;
268      src_sampler.wrap_t = src_wrap;
269      src_sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
270      src_sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
271      src_sampler.normalized_coords = 1;
272      samplers[0] = &src_sampler;
273      exa->bound_textures[0] = pSrc->tex;
274      ++exa->num_bound_samplers;
275   }
276
277   if (pMaskPicture && pMask) {
278      unsigned mask_wrap = render_repeat_to_gallium(
279         pMaskPicture->repeatType);
280      mask_sampler.wrap_s = mask_wrap;
281      mask_sampler.wrap_t = mask_wrap;
282      mask_sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
283      mask_sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
284      mask_sampler.normalized_coords = 1;
285      samplers[1] = &mask_sampler;
286      exa->bound_textures[1] = pMask->tex;
287      ++exa->num_bound_samplers;
288   }
289
290   cso_set_samplers(exa->renderer->cso, exa->num_bound_samplers,
291                    (const struct pipe_sampler_state **)samplers);
292   cso_set_sampler_textures(exa->renderer->cso, exa->num_bound_samplers,
293                            exa->bound_textures);
294}
295
296static void
297setup_vs_constant_buffer(struct exa_context *exa,
298                         int width, int height)
299{
300   const int param_bytes = 8 * sizeof(float);
301   float vs_consts[8] = {
302      2.f/width, 2.f/height, 1, 1,
303      -1, -1, 0, 0
304   };
305   renderer_set_constants(exa->renderer, PIPE_SHADER_VERTEX,
306                          vs_consts, param_bytes);
307}
308
309
310static void
311setup_fs_constant_buffer(struct exa_context *exa)
312{
313   const int param_bytes = 4 * sizeof(float);
314   const float fs_consts[8] = {
315      0, 0, 0, 1,
316   };
317   renderer_set_constants(exa->renderer, PIPE_SHADER_FRAGMENT,
318                          fs_consts, param_bytes);
319}
320
321static void
322setup_constant_buffers(struct exa_context *exa, struct exa_pixmap_priv *pDst)
323{
324   int width = pDst->tex->width[0];
325   int height = pDst->tex->height[0];
326
327   setup_vs_constant_buffer(exa, width, height);
328   setup_fs_constant_buffer(exa);
329}
330
331boolean xorg_composite_bind_state(struct exa_context *exa,
332                                  int op,
333                                  PicturePtr pSrcPicture,
334                                  PicturePtr pMaskPicture,
335                                  PicturePtr pDstPicture,
336                                  struct exa_pixmap_priv *pSrc,
337                                  struct exa_pixmap_priv *pMask,
338                                  struct exa_pixmap_priv *pDst)
339{
340   renderer_bind_framebuffer(exa->renderer, pDst);
341   renderer_bind_viewport(exa->renderer, pDst);
342   bind_blend_state(exa, op, pSrcPicture, pMaskPicture);
343   renderer_bind_rasterizer(exa->renderer);
344   bind_shaders(exa, op, pSrcPicture, pMaskPicture);
345   bind_samplers(exa, op, pSrcPicture, pMaskPicture,
346                 pDstPicture, pSrc, pMask, pDst);
347   setup_constant_buffers(exa, pDst);
348
349   return TRUE;
350}
351
352void xorg_composite(struct exa_context *exa,
353                    struct exa_pixmap_priv *dst,
354                    int srcX, int srcY, int maskX, int maskY,
355                    int dstX, int dstY, int width, int height)
356{
357   if (exa->num_bound_samplers == 0 ) { /* solid fill */
358      renderer_draw_solid_rect(exa->renderer,
359                               dstX, dstY, dstX + width, dstY + height,
360                               exa->solid_color);
361   } else {
362      int pos[6] = {srcX, srcY, maskX, maskY, dstX, dstY};
363      renderer_draw_textures(exa->renderer,
364                             pos, width, height,
365                             exa->bound_textures,
366                             exa->num_bound_samplers);
367   }
368}
369
370boolean xorg_solid_bind_state(struct exa_context *exa,
371                              struct exa_pixmap_priv *pixmap,
372                              Pixel fg)
373{
374   unsigned vs_traits, fs_traits;
375   struct xorg_shader shader;
376
377   pixel_to_float4(fg, exa->solid_color);
378   exa->has_solid_color = TRUE;
379
380#if 0
381   debug_printf("Color Pixel=(%d, %d, %d, %d), RGBA=(%f, %f, %f, %f)\n",
382                (fg >> 24) & 0xff, (fg >> 16) & 0xff,
383                (fg >> 8) & 0xff,  (fg >> 0) & 0xff,
384                exa->solid_color[0], exa->solid_color[1],
385                exa->solid_color[2], exa->solid_color[3]);
386#endif
387
388   vs_traits = VS_SOLID_FILL;
389   fs_traits = FS_SOLID_FILL;
390
391   renderer_bind_framebuffer(exa->renderer, pixmap);
392   renderer_bind_viewport(exa->renderer, pixmap);
393   renderer_bind_rasterizer(exa->renderer);
394   bind_blend_state(exa, PictOpSrc, NULL, NULL);
395   setup_constant_buffers(exa, pixmap);
396
397   shader = xorg_shaders_get(exa->renderer->shaders, vs_traits, fs_traits);
398   cso_set_vertex_shader_handle(exa->renderer->cso, shader.vs);
399   cso_set_fragment_shader_handle(exa->renderer->cso, shader.fs);
400
401   return TRUE;
402}
403
404void xorg_solid(struct exa_context *exa,
405                struct exa_pixmap_priv *pixmap,
406                int x0, int y0, int x1, int y1)
407{
408   renderer_draw_solid_rect(exa->renderer,
409                            x0, y0, x1, y1, exa->solid_color);
410}
411
412