xorg_composite.c revision d6b58a97c2f94ca54852414103c4ac2832279f2f
1#include "xorg_composite.h"
2
3#include "xorg_exa_tgsi.h"
4
5#include "cso_cache/cso_context.h"
6#include "util/u_draw_quad.h"
7
8#include "pipe/p_inlines.h"
9
10struct xorg_composite_blend {
11   int op:8;
12
13   unsigned rgb_src_factor:5;    /**< PIPE_BLENDFACTOR_x */
14   unsigned rgb_dst_factor:5;    /**< PIPE_BLENDFACTOR_x */
15
16   unsigned alpha_src_factor:5;  /**< PIPE_BLENDFACTOR_x */
17   unsigned alpha_dst_factor:5;  /**< PIPE_BLENDFACTOR_x */
18};
19
20#define BLEND_OP_OVER 3
21static const struct xorg_composite_blend xorg_blends[] = {
22   { PictOpClear,
23     PIPE_BLENDFACTOR_CONST_COLOR, PIPE_BLENDFACTOR_CONST_ALPHA,
24     PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO },
25
26   { PictOpSrc,
27     PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ONE,
28     PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO },
29
30   { PictOpDst,
31     PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO,
32     PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ONE },
33
34   { PictOpOver,
35     PIPE_BLENDFACTOR_SRC_ALPHA, PIPE_BLENDFACTOR_ONE,
36     PIPE_BLENDFACTOR_INV_SRC_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA },
37
38   { PictOpOverReverse,
39     PIPE_BLENDFACTOR_SRC_ALPHA, PIPE_BLENDFACTOR_ONE,
40     PIPE_BLENDFACTOR_INV_SRC_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA },
41};
42
43static INLINE void
44pixel_to_float4(PictFormatPtr format,
45                CARD32 pixel, float *color)
46{
47   CARD32	    r, g, b, a;
48
49   debug_assert(format->type == PictTypeDirect);
50
51   r = (pixel >> format->direct.red) & format->direct.redMask;
52   g = (pixel >> format->direct.green) & format->direct.greenMask;
53   b = (pixel >> format->direct.blue) & format->direct.blueMask;
54   a = (pixel >> format->direct.alpha) & format->direct.alphaMask;
55   color[0] = ((float)r) / ((float)format->direct.redMask);
56   color[1] = ((float)g) / ((float)format->direct.greenMask);
57   color[2] = ((float)b) / ((float)format->direct.blueMask);
58   color[3] = ((float)a) / ((float)format->direct.alphaMask);
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
115
116static INLINE void
117setup_vertex0(float vertex[2][4], float x, float y,
118              float color[4])
119{
120   vertex[0][0] = x;
121   vertex[0][1] = y;
122   vertex[0][2] = 0.f; /*z*/
123   vertex[0][3] = 1.f; /*w*/
124
125   vertex[1][0] = color[0]; /*r*/
126   vertex[1][1] = color[1]; /*g*/
127   vertex[1][2] = color[2]; /*b*/
128   vertex[1][3] = color[3]; /*a*/
129}
130
131static struct pipe_buffer *
132setup_vertex_data0(struct exa_context *ctx,
133                   int srcX, int srcY, int maskX, int maskY,
134                   int dstX, int dstY, int width, int height)
135{
136   float vertices[4][2][4];
137
138   /* 1st vertex */
139   setup_vertex0(vertices[0], dstX, dstY,
140                 ctx->solid_color);
141   /* 2nd vertex */
142   setup_vertex0(vertices[1], dstX + width, dstY,
143                 ctx->solid_color);
144   /* 3rd vertex */
145   setup_vertex0(vertices[2], dstX + width, dstY + height,
146                 ctx->solid_color);
147   /* 4th vertex */
148   setup_vertex0(vertices[3], dstX, dstY + height,
149                 ctx->solid_color);
150
151   return pipe_user_buffer_create(ctx->ctx->screen,
152                                  vertices,
153                                  sizeof(vertices));
154}
155
156static INLINE void
157setup_vertex1(float vertex[2][4], float x, float y, float s, float t)
158{
159   vertex[0][0] = x;
160   vertex[0][1] = y;
161   vertex[0][2] = 0.f; /*z*/
162   vertex[0][3] = 1.f; /*w*/
163
164   vertex[1][0] = s;   /*s*/
165   vertex[1][1] = t;   /*t*/
166   vertex[1][2] = 0.f; /*r*/
167   vertex[1][3] = 1.f; /*q*/
168}
169
170static struct pipe_buffer *
171setup_vertex_data1(struct exa_context *ctx,
172                   int srcX, int srcY, int maskX, int maskY,
173                   int dstX, int dstY, int width, int height)
174{
175   float vertices[4][2][4];
176   float s0, t0, s1, t1;
177   struct pipe_texture *src = ctx->bound_textures[0];
178
179   s0 = srcX / src->width[0];
180   s1 = srcX + width / src->width[0];
181   t0 = srcY / src->height[0];
182   t1 = srcY + height / src->height[0];
183
184   /* 1st vertex */
185   setup_vertex1(vertices[0], dstX, dstY,
186                 s0, t0);
187   /* 2nd vertex */
188   setup_vertex1(vertices[1], dstX + width, dstY,
189                 s1, t0);
190   /* 3rd vertex */
191   setup_vertex1(vertices[2], dstX + width, dstY + height,
192                 s1, t1);
193   /* 4th vertex */
194   setup_vertex1(vertices[3], dstX, dstY + height,
195                 s0, t1);
196
197   return pipe_user_buffer_create(ctx->ctx->screen,
198                                  vertices,
199                                  sizeof(vertices));
200}
201
202
203static INLINE void
204setup_vertex2(float vertex[3][4], float x, float y,
205              float s0, float t0, float s1, float t1)
206{
207   vertex[0][0] = x;
208   vertex[0][1] = y;
209   vertex[0][2] = 0.f; /*z*/
210   vertex[0][3] = 1.f; /*w*/
211
212   vertex[1][0] = s0;  /*s*/
213   vertex[1][1] = t0;  /*t*/
214   vertex[1][2] = 0.f; /*r*/
215   vertex[1][3] = 1.f; /*q*/
216
217   vertex[2][0] = s1;  /*s*/
218   vertex[2][1] = t1;  /*t*/
219   vertex[2][2] = 0.f; /*r*/
220   vertex[2][3] = 1.f; /*q*/
221}
222
223static struct pipe_buffer *
224setup_vertex_data2(struct exa_context *ctx,
225                   int srcX, int srcY, int maskX, int maskY,
226                   int dstX, int dstY, int width, int height)
227{
228   float vertices[4][3][4];
229   float st0[4], st1[4];
230   struct pipe_texture *src = ctx->bound_textures[0];
231   struct pipe_texture *mask = ctx->bound_textures[0];
232
233   st0[0] = srcX / src->width[0];
234   st0[1] = srcY / src->height[0];
235   st0[2] = srcX + width / src->width[0];
236   st0[3] = srcY + height / src->height[0];
237
238   st1[0] = maskX / mask->width[0];
239   st1[1] = maskY / mask->height[0];
240   st1[2] = maskX + width / mask->width[0];
241   st1[3] = maskY + height / mask->height[0];
242
243   /* 1st vertex */
244   setup_vertex2(vertices[0], dstX, dstY,
245                 st0[0], st0[1], st1[0], st1[1]);
246   /* 2nd vertex */
247   setup_vertex2(vertices[1], dstX + width, dstY,
248                 st0[2], st0[1], st1[2], st1[1]);
249   /* 3rd vertex */
250   setup_vertex2(vertices[2], dstX + width, dstY + height,
251                 st0[2], st0[3], st1[2], st1[3]);
252   /* 4th vertex */
253   setup_vertex2(vertices[3], dstX, dstY + height,
254                 st0[0], st0[3], st1[0], st1[3]);
255
256   return pipe_user_buffer_create(ctx->ctx->screen,
257                                  vertices,
258                                  sizeof(vertices));
259}
260
261boolean xorg_composite_accelerated(int op,
262                                   PicturePtr pSrcPicture,
263                                   PicturePtr pMaskPicture,
264                                   PicturePtr pDstPicture)
265{
266   unsigned i;
267   unsigned accel_ops_count =
268      sizeof(accelerated_ops)/sizeof(struct acceleration_info);
269
270
271   /*FIXME: currently accel is disabled */
272   return FALSE;
273
274   if (pSrcPicture) {
275      /* component alpha not supported */
276      if (pSrcPicture->componentAlpha)
277         return FALSE;
278      /* fills not supported */
279      if (pSrcPicture->pSourcePict)
280         return FALSE;
281   }
282
283   for (i = 0; i < accel_ops_count; ++i) {
284      if (op == accelerated_ops[i].op) {
285         if (pMaskPicture && !accelerated_ops[i].with_mask)
286            return FALSE;
287         return TRUE;
288      }
289   }
290   return FALSE;
291}
292
293static void
294bind_framebuffer_state(struct exa_context *exa, PicturePtr pDstPicture,
295                       struct exa_pixmap_priv *pDst)
296{
297   unsigned i;
298   struct pipe_framebuffer_state state;
299   struct pipe_surface *surface = exa_gpu_surface(exa, pDst);
300   memset(&state, 0, sizeof(struct pipe_framebuffer_state));
301
302   state.width  = pDstPicture->pDrawable->width;
303   state.height = pDstPicture->pDrawable->height;
304
305   state.nr_cbufs = 1;
306   state.cbufs[0] = surface;
307   for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i)
308      state.cbufs[i] = 0;
309
310   /* currently we don't use depth/stencil */
311   state.zsbuf = 0;
312
313   cso_set_framebuffer(exa->cso, &state);
314}
315
316enum AxisOrientation {
317   Y0_BOTTOM,
318   Y0_TOP
319};
320
321static void
322set_viewport(struct exa_context *exa, int width, int height,
323             enum AxisOrientation orientation)
324{
325   struct pipe_viewport_state viewport;
326   float y_scale = (orientation == Y0_BOTTOM) ? -2.f : 2.f;
327
328   viewport.scale[0] =  width / 2.f;
329   viewport.scale[1] =  height / y_scale;
330   viewport.scale[2] =  1.0;
331   viewport.scale[3] =  1.0;
332   viewport.translate[0] = width / 2.f;
333   viewport.translate[1] = height / 2.f;
334   viewport.translate[2] = 0.0;
335   viewport.translate[3] = 0.0;
336
337   cso_set_viewport(exa->cso, &viewport);
338}
339
340static void
341bind_viewport_state(struct exa_context *exa, PicturePtr pDstPicture)
342{
343   int width = pDstPicture->pDrawable->width;
344   int height = pDstPicture->pDrawable->height;
345
346   set_viewport(exa, width, height, Y0_TOP);
347}
348
349static void
350bind_blend_state(struct exa_context *exa, int op,
351                 PicturePtr pSrcPicture, PicturePtr pMaskPicture)
352{
353   boolean component_alpha = pSrcPicture->componentAlpha;
354   struct xorg_composite_blend blend_opt;
355   struct pipe_blend_state blend;
356
357   if (component_alpha) {
358      op = PictOpOver;
359   }
360   blend_opt = blend_for_op(op);
361
362   memset(&blend, 0, sizeof(struct pipe_blend_state));
363   blend.blend_enable = 1;
364   blend.colormask |= PIPE_MASK_R;
365   blend.colormask |= PIPE_MASK_G;
366   blend.colormask |= PIPE_MASK_B;
367   blend.colormask |= PIPE_MASK_A;
368
369   blend.rgb_src_factor   = blend_opt.rgb_src_factor;
370   blend.alpha_src_factor = blend_opt.alpha_src_factor;
371   blend.rgb_dst_factor   = blend_opt.rgb_dst_factor;
372   blend.alpha_dst_factor = blend_opt.alpha_dst_factor;
373
374   cso_set_blend(exa->cso, &blend);
375}
376
377static void
378bind_rasterizer_state(struct exa_context *exa)
379{
380   struct pipe_rasterizer_state raster;
381   memset(&raster, 0, sizeof(struct pipe_rasterizer_state));
382   raster.gl_rasterization_rules = 1;
383   cso_set_rasterizer(exa->cso, &raster);
384}
385
386static void
387bind_shaders(struct exa_context *exa, int op,
388             PicturePtr pSrcPicture, PicturePtr pMaskPicture)
389{
390   unsigned vs_traits = 0, fs_traits = 0;
391   struct xorg_shader shader;
392
393   if (pSrcPicture) {
394      if (pSrcPicture->pSourcePict) {
395         if (pSrcPicture->pSourcePict->type == SourcePictTypeSolidFill) {
396            fs_traits |= FS_FILL;
397            vs_traits |= VS_FILL;
398            pixel_to_float4(pSrcPicture->pFormat,
399                            pSrcPicture->pSourcePict->solidFill.color,
400                            exa->solid_color);
401         } else {
402            debug_assert("!gradients not supported");
403         }
404      } else {
405         fs_traits |= FS_COMPOSITE;
406         vs_traits |= VS_COMPOSITE;
407      }
408   }
409
410   if (pMaskPicture) {
411      vs_traits |= VS_MASK;
412      fs_traits |= FS_MASK;
413   }
414
415   shader = xorg_shaders_get(exa->shaders, vs_traits, fs_traits);
416   cso_set_vertex_shader_handle(exa->cso, shader.vs);
417   cso_set_fragment_shader_handle(exa->cso, shader.fs);
418}
419
420
421static void
422bind_samplers(struct exa_context *exa, int op,
423              PicturePtr pSrcPicture, PicturePtr pMaskPicture,
424              PicturePtr pDstPicture,
425              struct exa_pixmap_priv *pSrc,
426              struct exa_pixmap_priv *pMask,
427              struct exa_pixmap_priv *pDst)
428{
429   struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS];
430   struct pipe_sampler_state src_sampler, mask_sampler;
431
432   exa->num_bound_samplers = 0;
433
434   memset(&src_sampler, 0, sizeof(struct pipe_sampler_state));
435   memset(&mask_sampler, 0, sizeof(struct pipe_sampler_state));
436
437   if (pSrcPicture && pSrc) {
438      unsigned src_wrap = render_repeat_to_gallium(
439         pSrcPicture->repeatType);
440      src_sampler.wrap_s = src_wrap;
441      src_sampler.wrap_t = src_wrap;
442      src_sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
443      src_sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
444      src_sampler.normalized_coords = 1;
445      samplers[0] = &src_sampler;
446      exa->bound_textures[0] = pSrc->tex;
447      ++exa->num_bound_samplers;
448   }
449
450   if (pMaskPicture && pMask) {
451      unsigned mask_wrap = render_repeat_to_gallium(
452         pMaskPicture->repeatType);
453      mask_sampler.wrap_s = mask_wrap;
454      mask_sampler.wrap_t = mask_wrap;
455      mask_sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
456      mask_sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
457      mask_sampler.normalized_coords = 1;
458      samplers[1] = &mask_sampler;
459      exa->bound_textures[1] = pMask->tex;
460      ++exa->num_bound_samplers;
461   }
462
463   cso_set_samplers(exa->cso, exa->num_bound_samplers,
464                    (const struct pipe_sampler_state **)samplers);
465   cso_set_sampler_textures(exa->cso, exa->num_bound_samplers,
466                            exa->bound_textures);
467}
468
469static void
470setup_vs_constant_buffer(struct exa_context *exa,
471                         int width, int height)
472{
473   const int param_bytes = 8 * sizeof(float);
474   float vs_consts[8] = {
475      2.f/width, 2.f/height, 1, 1,
476      -1, -1, 0, 0
477   };
478   struct pipe_constant_buffer *cbuf = &exa->vs_const_buffer;
479
480   pipe_buffer_reference(&cbuf->buffer, NULL);
481   cbuf->buffer = pipe_buffer_create(exa->ctx->screen, 16,
482                                     PIPE_BUFFER_USAGE_CONSTANT,
483                                     param_bytes);
484
485   if (cbuf->buffer) {
486      pipe_buffer_write(exa->ctx->screen, cbuf->buffer,
487                        0, param_bytes, vs_consts);
488   }
489   exa->ctx->set_constant_buffer(exa->ctx, PIPE_SHADER_VERTEX, 0, cbuf);
490}
491
492
493static void
494setup_fs_constant_buffer(struct exa_context *exa)
495{
496   const int param_bytes = 4 * sizeof(float);
497   float fs_consts[8] = {
498      0, 0, 0, 1,
499   };
500   struct pipe_constant_buffer *cbuf = &exa->fs_const_buffer;
501
502   pipe_buffer_reference(&cbuf->buffer, NULL);
503   cbuf->buffer = pipe_buffer_create(exa->ctx->screen, 16,
504                                     PIPE_BUFFER_USAGE_CONSTANT,
505                                     param_bytes);
506
507   if (cbuf->buffer) {
508      pipe_buffer_write(exa->ctx->screen, cbuf->buffer,
509                        0, param_bytes, fs_consts);
510   }
511   exa->ctx->set_constant_buffer(exa->ctx, PIPE_SHADER_FRAGMENT, 0, cbuf);
512}
513
514static void
515setup_constant_buffers(struct exa_context *exa, PicturePtr pDstPicture)
516{
517   int width = pDstPicture->pDrawable->width;
518   int height = pDstPicture->pDrawable->height;
519
520   setup_vs_constant_buffer(exa, width, height);
521   setup_fs_constant_buffer(exa);
522}
523
524boolean xorg_composite_bind_state(struct exa_context *exa,
525                                  int op,
526                                  PicturePtr pSrcPicture,
527                                  PicturePtr pMaskPicture,
528                                  PicturePtr pDstPicture,
529                                  struct exa_pixmap_priv *pSrc,
530                                  struct exa_pixmap_priv *pMask,
531                                  struct exa_pixmap_priv *pDst)
532{
533   bind_framebuffer_state(exa, pDstPicture, pDst);
534   bind_viewport_state(exa, pDstPicture);
535   bind_blend_state(exa, op, pSrcPicture, pMaskPicture);
536   bind_rasterizer_state(exa);
537   bind_shaders(exa, op, pSrcPicture, pMaskPicture);
538   bind_samplers(exa, op, pSrcPicture, pMaskPicture,
539                 pDstPicture, pSrc, pMask, pDst);
540
541   setup_constant_buffers(exa, pDstPicture);
542
543   return FALSE;
544}
545
546void xorg_composite(struct exa_context *exa,
547                    struct exa_pixmap_priv *dst,
548                    int srcX, int srcY, int maskX, int maskY,
549                    int dstX, int dstY, int width, int height)
550{
551   struct pipe_context *pipe = exa->ctx;
552   struct pipe_buffer *buf = 0;
553
554   if (exa->num_bound_samplers == 0 ) { /* solid fill */
555      buf = setup_vertex_data0(exa,
556                               srcX, srcY, maskX, maskY,
557                               dstX, dstY, width, height);
558   } else if (exa->num_bound_samplers == 1 ) /* src */
559      buf = setup_vertex_data1(exa,
560                               srcX, srcY, maskX, maskY,
561                               dstX, dstY, width, height);
562   else if (exa->num_bound_samplers == 2) /* src + mask */
563      buf = setup_vertex_data2(exa,
564                               srcX, srcY, maskX, maskY,
565                               dstX, dstY, width, height);
566   else if (exa->num_bound_samplers == 3) { /* src + mask + dst */
567      debug_assert(!"src/mask/dst not handled right now");
568#if 0
569      buf = setup_vertex_data2(exa,
570                               srcX, srcY, maskX, maskY,
571                               dstX, dstY, width, height);
572#endif
573   }
574
575   if (buf) {
576      util_draw_vertex_buffer(pipe, buf, 0,
577                              PIPE_PRIM_TRIANGLE_FAN,
578                              4,  /* verts */
579                              1 + exa->num_bound_samplers); /* attribs/vert */
580
581      pipe_buffer_reference(&buf, NULL);
582   }
583}
584
585