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