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