xorg_composite.c revision 91c366359ce0bf5f450fd1d774b771c95ed2f651
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
43struct acceleration_info {
44   int op : 16;
45   int with_mask : 1;
46   int component_alpha : 1;
47};
48static const struct acceleration_info accelerated_ops[] = {
49   {PictOpClear,       1, 0},
50   {PictOpSrc,         1, 0},
51   {PictOpDst,         1, 0},
52   {PictOpOver,        1, 0},
53   {PictOpOverReverse, 1, 0},
54   {PictOpIn,          1, 0},
55   {PictOpInReverse,   1, 0},
56   {PictOpOut,         1, 0},
57   {PictOpOutReverse,  1, 0},
58   {PictOpAtop,        1, 0},
59   {PictOpAtopReverse, 1, 0},
60   {PictOpXor,         1, 0},
61   {PictOpAdd,         1, 0},
62   {PictOpSaturate,    1, 0},
63};
64
65static struct xorg_composite_blend
66blend_for_op(int op)
67{
68   const int num_blends =
69      sizeof(xorg_blends)/sizeof(struct xorg_composite_blend);
70   int i;
71
72   for (i = 0; i < num_blends; ++i) {
73      if (xorg_blends[i].op == op)
74         return xorg_blends[i];
75   }
76   return xorg_blends[BLEND_OP_OVER];
77}
78
79
80static INLINE void
81setup_vertex0(float vertex[2][4], float x, float y,
82              float color[4])
83{
84   vertex[0][0] = x;
85   vertex[0][1] = y;
86   vertex[0][2] = 0.f; /*z*/
87   vertex[0][3] = 1.f; /*w*/
88
89   vertex[1][0] = color[0]; /*r*/
90   vertex[1][1] = color[1]; /*g*/
91   vertex[1][2] = color[2]; /*b*/
92   vertex[1][3] = color[3]; /*a*/
93}
94
95static struct pipe_buffer *
96setup_vertex_data0(struct exa_context *ctx,
97                   int srcX, int srcY, int maskX, int maskY,
98                   int dstX, int dstY, int width, int height)
99{
100   float vertices[4][2][4];
101
102   /* 1st vertex */
103   setup_vertex0(vertices[0], dstX, dstY,
104                 ctx->solid_color);
105   /* 2nd vertex */
106   setup_vertex0(vertices[1], dstX + width, dstY,
107                 ctx->solid_color);
108   /* 3rd vertex */
109   setup_vertex0(vertices[2], dstX + width, dstY + height,
110                 ctx->solid_color);
111   /* 4th vertex */
112   setup_vertex0(vertices[3], dstX, dstY + height,
113                 ctx->solid_color);
114
115   return pipe_user_buffer_create(ctx->ctx->screen,
116                                  vertices,
117                                  sizeof(vertices));
118}
119
120static INLINE void
121setup_vertex1(float vertex[2][4], float x, float y, float s, float t)
122{
123   vertex[0][0] = x;
124   vertex[0][1] = y;
125   vertex[0][2] = 0.f; /*z*/
126   vertex[0][3] = 1.f; /*w*/
127
128   vertex[1][0] = s;   /*s*/
129   vertex[1][1] = t;   /*t*/
130   vertex[1][2] = 0.f; /*r*/
131   vertex[1][3] = 1.f; /*q*/
132}
133
134static struct pipe_buffer *
135setup_vertex_data1(struct exa_context *ctx,
136                   int srcX, int srcY, int maskX, int maskY,
137                   int dstX, int dstY, int width, int height)
138{
139   float vertices[4][2][4];
140   float s0, t0, s1, t1;
141   struct pipe_texture *src = ctx->bound_textures[0];
142
143   s0 = srcX / src->width[0];
144   s1 = srcX + width / src->width[0];
145   t0 = srcY / src->height[0];
146   t1 = srcY + height / src->height[0];
147
148   /* 1st vertex */
149   setup_vertex1(vertices[0], dstX, dstY,
150                 s0, t0);
151   /* 2nd vertex */
152   setup_vertex1(vertices[1], dstX + width, dstY,
153                 s1, t0);
154   /* 3rd vertex */
155   setup_vertex1(vertices[2], dstX + width, dstY + height,
156                 s1, t1);
157   /* 4th vertex */
158   setup_vertex1(vertices[3], dstX, dstY + height,
159                 s0, t1);
160
161   return pipe_user_buffer_create(ctx->ctx->screen,
162                                  vertices,
163                                  sizeof(vertices));
164}
165
166
167static INLINE void
168setup_vertex2(float vertex[3][4], float x, float y,
169              float s0, float t0, float s1, float t1)
170{
171   vertex[0][0] = x;
172   vertex[0][1] = y;
173   vertex[0][2] = 0.f; /*z*/
174   vertex[0][3] = 1.f; /*w*/
175
176   vertex[1][0] = s0;  /*s*/
177   vertex[1][1] = t0;  /*t*/
178   vertex[1][2] = 0.f; /*r*/
179   vertex[1][3] = 1.f; /*q*/
180
181   vertex[2][0] = s1;  /*s*/
182   vertex[2][1] = t1;  /*t*/
183   vertex[2][2] = 0.f; /*r*/
184   vertex[2][3] = 1.f; /*q*/
185}
186
187static struct pipe_buffer *
188setup_vertex_data2(struct exa_context *ctx,
189                   int srcX, int srcY, int maskX, int maskY,
190                   int dstX, int dstY, int width, int height)
191{
192   float vertices[4][3][4];
193   float st0[4], st1[4];
194   struct pipe_texture *src = ctx->bound_textures[0];
195   struct pipe_texture *mask = ctx->bound_textures[0];
196
197   st0[0] = srcX / src->width[0];
198   st0[1] = srcY / src->height[0];
199   st0[2] = srcX + width / src->width[0];
200   st0[3] = srcY + height / src->height[0];
201
202   st1[0] = maskX / mask->width[0];
203   st1[1] = maskY / mask->height[0];
204   st1[2] = maskX + width / mask->width[0];
205   st1[3] = maskY + height / mask->height[0];
206
207   /* 1st vertex */
208   setup_vertex2(vertices[0], dstX, dstY,
209                 st0[0], st0[1], st1[0], st1[1]);
210   /* 2nd vertex */
211   setup_vertex2(vertices[1], dstX + width, dstY,
212                 st0[2], st0[1], st1[2], st1[1]);
213   /* 3rd vertex */
214   setup_vertex2(vertices[2], dstX + width, dstY + height,
215                 st0[2], st0[3], st1[2], st1[3]);
216   /* 4th vertex */
217   setup_vertex2(vertices[3], dstX, dstY + height,
218                 st0[0], st0[3], st1[0], st1[3]);
219
220   return pipe_user_buffer_create(ctx->ctx->screen,
221                                  vertices,
222                                  sizeof(vertices));
223}
224
225
226static void
227draw_pictures(struct exa_context *exa,
228              int srcX, int srcY, int maskX, int maskY,
229              int dstX, int dstY, int width, int height)
230{
231   struct pipe_context *pipe = exa->ctx;
232   struct pipe_buffer *buf = 0;
233
234   if (exa->num_bound_samplers == 0 ) { /* solid fill */
235      buf = setup_vertex_data0(exa,
236                               srcX, srcY, maskX, maskY,
237                               dstX, dstY, width, height);
238   } else if (exa->num_bound_samplers == 1 ) /* src */
239      buf = setup_vertex_data1(exa,
240                               srcX, srcY, maskX, maskY,
241                               dstX, dstY, width, height);
242   else if (exa->num_bound_samplers == 2) /* src + mask */
243      buf = setup_vertex_data2(exa,
244                               srcX, srcY, maskX, maskY,
245                               dstX, dstY, width, height);
246   else if (exa->num_bound_samplers == 3) { /* src + mask + dst */
247      debug_assert(!"src/mask/dst not handled right now");
248#if 0
249      buf = setup_vertex_data2(exa,
250                               srcX, srcY, maskX, maskY,
251                               dstX, dstY, width, height);
252#endif
253   }
254
255   if (buf) {
256      util_draw_vertex_buffer(pipe, buf, 0,
257                              PIPE_PRIM_TRIANGLE_FAN,
258                              4,  /* verts */
259                              1 + exa->num_bound_samplers); /* attribs/vert */
260
261      pipe_buffer_reference(&buf, NULL);
262   }
263}
264
265boolean xorg_composite_accelerated(int op,
266                                   PicturePtr pSrcPicture,
267                                   PicturePtr pMaskPicture,
268                                   PicturePtr pDstPicture)
269{
270   unsigned i;
271   unsigned accel_ops_count =
272      sizeof(accelerated_ops)/sizeof(struct acceleration_info);
273
274
275   /*FIXME: currently accel is disabled */
276   return FALSE;
277
278   if (pSrcPicture) {
279      /* component alpha not supported */
280      if (pSrcPicture->componentAlpha)
281         return FALSE;
282      /* fills not supported */
283      if (pSrcPicture->pSourcePict)
284         return FALSE;
285   }
286
287   for (i = 0; i < accel_ops_count; ++i) {
288      if (op == accelerated_ops[i].op) {
289         if (pMaskPicture && !accelerated_ops[i].with_mask)
290            return FALSE;
291         return TRUE;
292      }
293   }
294   return FALSE;
295}
296
297static void
298bind_framebuffer_state(struct exa_context *exa, PicturePtr pDstPicture,
299                       struct exa_pixmap_priv *pDst)
300{
301   unsigned i;
302   struct pipe_framebuffer_state state;
303   struct pipe_surface *surface = exa_gpu_surface(exa, pDst);
304   memset(&state, 0, sizeof(struct pipe_framebuffer_state));
305
306   state.width  = pDstPicture->pDrawable->width;
307   state.height = pDstPicture->pDrawable->height;
308
309   state.nr_cbufs = 1;
310   state.cbufs[0] = surface;
311   for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i)
312      state.cbufs[i] = 0;
313
314   /* currently we don't use depth/stencil */
315   state.zsbuf = 0;
316
317   cso_set_framebuffer(exa->cso, &state);
318}
319
320enum AxisOrientation {
321   Y0_BOTTOM,
322   Y0_TOP
323};
324
325static void
326set_viewport(struct exa_context *exa, int width, int height,
327             enum AxisOrientation orientation)
328{
329   struct pipe_viewport_state viewport;
330   float y_scale = (orientation == Y0_BOTTOM) ? -2.f : 2.f;
331
332   viewport.scale[0] =  width / 2.f;
333   viewport.scale[1] =  height / y_scale;
334   viewport.scale[2] =  1.0;
335   viewport.scale[3] =  1.0;
336   viewport.translate[0] = width / 2.f;
337   viewport.translate[1] = height / 2.f;
338   viewport.translate[2] = 0.0;
339   viewport.translate[3] = 0.0;
340
341   cso_set_viewport(exa->cso, &viewport);
342}
343
344static void
345bind_viewport_state(struct exa_context *exa, PicturePtr pDstPicture)
346{
347   int width = pDstPicture->pDrawable->width;
348   int height = pDstPicture->pDrawable->height;
349
350   set_viewport(exa, width, height, Y0_BOTTOM);
351}
352
353static void
354bind_blend_state(struct exa_context *exa, int op,
355                 PicturePtr pSrcPicture, PicturePtr pMaskPicture)
356{
357   boolean component_alpha = pSrcPicture->componentAlpha;
358   struct xorg_composite_blend blend_opt;
359   struct pipe_blend_state blend;
360
361   if (component_alpha) {
362      op = PictOpOver;
363   }
364   blend_opt = blend_for_op(op);
365
366   memset(&blend, 0, sizeof(struct pipe_blend_state));
367   blend.blend_enable = 1;
368   blend.colormask |= PIPE_MASK_R;
369   blend.colormask |= PIPE_MASK_G;
370   blend.colormask |= PIPE_MASK_B;
371   blend.colormask |= PIPE_MASK_A;
372
373   blend.rgb_src_factor   = blend_opt.rgb_src_factor;
374   blend.alpha_src_factor = blend_opt.alpha_src_factor;
375   blend.rgb_dst_factor   = blend_opt.rgb_dst_factor;
376   blend.alpha_dst_factor = blend_opt.alpha_dst_factor;
377
378   cso_set_blend(exa->cso, &blend);
379}
380
381static void
382bind_rasterizer_state(struct exa_context *exa)
383{
384   struct pipe_rasterizer_state raster;
385   memset(&raster, 0, sizeof(struct pipe_rasterizer_state));
386   raster.gl_rasterization_rules = 1;
387   cso_set_rasterizer(exa->cso, &raster);
388}
389
390static void
391bind_shaders(struct exa_context *exa, int op,
392             PicturePtr pSrcPicture, PicturePtr pMaskPicture)
393{
394   unsigned vs_traits = 0, fs_traits = 0;
395   struct xorg_shader shader;
396
397   if (pSrcPicture) {
398      vs_traits |= VS_COMPOSITE;
399      fs_traits |= FS_COMPOSITE;
400   }
401
402   if (pMaskPicture) {
403      vs_traits |= VS_MASK;
404      fs_traits |= FS_MASK;
405   }
406
407   shader = xorg_shaders_get(exa->shaders, vs_traits, fs_traits);
408   cso_set_vertex_shader_handle(exa->cso, shader.vs);
409   cso_set_fragment_shader_handle(exa->cso, shader.fs);
410}
411
412
413static void
414bind_samplers(struct exa_context *exa, int op,
415              PicturePtr pSrcPicture, PicturePtr pMaskPicture,
416              PicturePtr pDstPicture,
417              struct exa_pixmap_priv *pSrc,
418              struct exa_pixmap_priv *pMask,
419              struct exa_pixmap_priv *pDst)
420{
421   struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS];
422   struct pipe_sampler_state src_sampler, mask_sampler;
423
424   exa->num_bound_samplers = 0;
425
426   memset(&src_sampler, 0, sizeof(struct pipe_sampler_state));
427   memset(&mask_sampler, 0, sizeof(struct pipe_sampler_state));
428
429   if (pSrcPicture && pSrc) {
430      src_sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
431      src_sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
432      src_sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
433      src_sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
434      src_sampler.normalized_coords = 1;
435      samplers[0] = &src_sampler;
436      exa->bound_textures[0] = pSrc->tex;
437      ++exa->num_bound_samplers;
438   }
439
440   if (pMaskPicture && pMask) {
441      mask_sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
442      mask_sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
443      mask_sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
444      mask_sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
445      mask_sampler.normalized_coords = 1;
446      samplers[1] = &mask_sampler;
447      exa->bound_textures[1] = pMask->tex;
448      ++exa->num_bound_samplers;
449   }
450
451   cso_set_samplers(exa->cso, exa->num_bound_samplers,
452                    (const struct pipe_sampler_state **)samplers);
453   cso_set_sampler_textures(exa->cso, exa->num_bound_samplers,
454                            exa->bound_textures);
455}
456
457static void
458setup_vs_constant_buffer(struct exa_context *exa,
459                         int width, int height)
460{
461   const int param_bytes = 8 * sizeof(float);
462   float vs_consts[8] = {
463      2.f/width, 2.f/height, 1, 1,
464      -1, -1, 0, 0
465   };
466   struct pipe_constant_buffer *cbuf = &exa->vs_const_buffer;
467
468   pipe_buffer_reference(&cbuf->buffer, NULL);
469   cbuf->buffer = pipe_buffer_create(exa->ctx->screen, 16,
470                                     PIPE_BUFFER_USAGE_CONSTANT,
471                                     param_bytes);
472
473   if (cbuf->buffer) {
474      pipe_buffer_write(exa->ctx->screen, cbuf->buffer,
475                        0, param_bytes, vs_consts);
476   }
477   exa->ctx->set_constant_buffer(exa->ctx, PIPE_SHADER_VERTEX, 0, cbuf);
478}
479
480
481static void
482setup_fs_constant_buffer(struct exa_context *exa)
483{
484   const int param_bytes = 4 * sizeof(float);
485   float fs_consts[8] = {
486      0, 0, 0, 1,
487   };
488   struct pipe_constant_buffer *cbuf = &exa->fs_const_buffer;
489
490   pipe_buffer_reference(&cbuf->buffer, NULL);
491   cbuf->buffer = pipe_buffer_create(exa->ctx->screen, 16,
492                                     PIPE_BUFFER_USAGE_CONSTANT,
493                                     param_bytes);
494
495   if (cbuf->buffer) {
496      pipe_buffer_write(exa->ctx->screen, cbuf->buffer,
497                        0, param_bytes, fs_consts);
498   }
499   exa->ctx->set_constant_buffer(exa->ctx, PIPE_SHADER_FRAGMENT, 0, cbuf);
500}
501
502static void
503setup_constant_buffers(struct exa_context *exa, PicturePtr pDstPicture)
504{
505   int width = pDstPicture->pDrawable->width;
506   int height = pDstPicture->pDrawable->height;
507
508   setup_vs_constant_buffer(exa, width, height);
509   setup_fs_constant_buffer(exa);
510}
511
512boolean xorg_composite_bind_state(struct exa_context *exa,
513                                  int op,
514                                  PicturePtr pSrcPicture,
515                                  PicturePtr pMaskPicture,
516                                  PicturePtr pDstPicture,
517                                  struct exa_pixmap_priv *pSrc,
518                                  struct exa_pixmap_priv *pMask,
519                                  struct exa_pixmap_priv *pDst)
520{
521   bind_framebuffer_state(exa, pDstPicture, pDst);
522   bind_viewport_state(exa, pDstPicture);
523   bind_blend_state(exa, op, pSrcPicture, pMaskPicture);
524   bind_rasterizer_state(exa);
525   bind_shaders(exa, op, pSrcPicture, pMaskPicture);
526   bind_samplers(exa, op, pSrcPicture, pMaskPicture,
527                 pDstPicture, pSrc, pMask, pDst);
528
529   setup_constant_buffers(exa, pDstPicture);
530
531   return FALSE;
532}
533
534void xorg_composite(struct exa_context *exa,
535                    struct exa_pixmap_priv *dst,
536                    int srcX, int srcY, int maskX, int maskY,
537                    int dstX, int dstY, int width, int height)
538{
539   draw_pictures(exa, srcX, srcY, maskX, maskY,
540                 dstX, dstY, width, height);
541}
542
543