xorg_composite.c revision 53d2fa46e7fa19d0cb7dec74efcd407ab6163c80
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#include "util/u_math.h"
8
9#include "pipe/p_inlines.h"
10
11struct xorg_composite_blend {
12   int op:8;
13
14   unsigned rgb_src_factor:5;    /**< PIPE_BLENDFACTOR_x */
15   unsigned alpha_src_factor:5;  /**< PIPE_BLENDFACTOR_x */
16
17   unsigned rgb_dst_factor:5;    /**< PIPE_BLENDFACTOR_x */
18   unsigned alpha_dst_factor:5;  /**< PIPE_BLENDFACTOR_x */
19};
20
21#define BLEND_OP_OVER 3
22static const struct xorg_composite_blend xorg_blends[] = {
23   { PictOpClear,
24     PIPE_BLENDFACTOR_CONST_COLOR, PIPE_BLENDFACTOR_CONST_ALPHA,
25     PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO },
26
27   { PictOpSrc,
28     PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ONE,
29     PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO },
30
31   { PictOpDst,
32     PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO,
33     PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ONE },
34
35   { PictOpOver,
36     PIPE_BLENDFACTOR_SRC_ALPHA, PIPE_BLENDFACTOR_ONE,
37     PIPE_BLENDFACTOR_INV_SRC_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA },
38
39   { PictOpOverReverse,
40     PIPE_BLENDFACTOR_SRC_ALPHA, PIPE_BLENDFACTOR_ONE,
41     PIPE_BLENDFACTOR_INV_SRC_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA },
42};
43
44
45static INLINE void
46pixel_to_float4(Pixel pixel, float *color)
47{
48   CARD32	    r, g, b, a;
49
50   a = (pixel >> 24) & 0xff;
51   r = (pixel >> 16) & 0xff;
52   g = (pixel >>  8) & 0xff;
53   b = (pixel >>  0) & 0xff;
54   color[0] = ((float)r) / 255.;
55   color[1] = ((float)g) / 255.;
56   color[2] = ((float)b) / 255.;
57   color[3] = ((float)a) / 255.;
58}
59
60static INLINE void
61render_pixel_to_float4(PictFormatPtr format,
62                       CARD32 pixel, float *color)
63{
64   CARD32	    r, g, b, a;
65
66   debug_assert(format->type == PictTypeDirect);
67
68   r = (pixel >> format->direct.red) & format->direct.redMask;
69   g = (pixel >> format->direct.green) & format->direct.greenMask;
70   b = (pixel >> format->direct.blue) & format->direct.blueMask;
71   a = (pixel >> format->direct.alpha) & format->direct.alphaMask;
72   color[0] = ((float)r) / ((float)format->direct.redMask);
73   color[1] = ((float)g) / ((float)format->direct.greenMask);
74   color[2] = ((float)b) / ((float)format->direct.blueMask);
75   color[3] = ((float)a) / ((float)format->direct.alphaMask);
76}
77
78struct acceleration_info {
79   int op : 16;
80   int with_mask : 1;
81   int component_alpha : 1;
82};
83static const struct acceleration_info accelerated_ops[] = {
84   {PictOpClear,       1, 0},
85   {PictOpSrc,         1, 0},
86   {PictOpDst,         1, 0},
87   {PictOpOver,        1, 0},
88   {PictOpOverReverse, 1, 0},
89   {PictOpIn,          1, 0},
90   {PictOpInReverse,   1, 0},
91   {PictOpOut,         1, 0},
92   {PictOpOutReverse,  1, 0},
93   {PictOpAtop,        1, 0},
94   {PictOpAtopReverse, 1, 0},
95   {PictOpXor,         1, 0},
96   {PictOpAdd,         1, 0},
97   {PictOpSaturate,    1, 0},
98};
99
100static struct xorg_composite_blend
101blend_for_op(int op)
102{
103   const int num_blends =
104      sizeof(xorg_blends)/sizeof(struct xorg_composite_blend);
105   int i;
106
107   for (i = 0; i < num_blends; ++i) {
108      if (xorg_blends[i].op == op)
109         return xorg_blends[i];
110   }
111   return xorg_blends[BLEND_OP_OVER];
112}
113
114static INLINE int
115render_repeat_to_gallium(int mode)
116{
117   switch(mode) {
118   case RepeatNone:
119      return PIPE_TEX_WRAP_CLAMP;
120   case RepeatNormal:
121      return PIPE_TEX_WRAP_REPEAT;
122   case RepeatReflect:
123      return PIPE_TEX_WRAP_MIRROR_REPEAT;
124   case RepeatPad:
125      return PIPE_TEX_WRAP_CLAMP_TO_EDGE;
126   default:
127      debug_printf("Unsupported repeat mode\n");
128   }
129   return PIPE_TEX_WRAP_REPEAT;
130}
131
132
133static INLINE void
134setup_vertex0(float vertex[2][4], float x, float y,
135              float color[4])
136{
137   vertex[0][0] = x;
138   vertex[0][1] = y;
139   vertex[0][2] = 0.f; /*z*/
140   vertex[0][3] = 1.f; /*w*/
141
142   vertex[1][0] = color[0]; /*r*/
143   vertex[1][1] = color[1]; /*g*/
144   vertex[1][2] = color[2]; /*b*/
145   vertex[1][3] = color[3]; /*a*/
146}
147
148static struct pipe_buffer *
149setup_vertex_data0(struct exa_context *ctx,
150                   int srcX, int srcY, int maskX, int maskY,
151                   int dstX, int dstY, int width, int height)
152{
153   /* 1st vertex */
154   setup_vertex0(ctx->vertices2[0], dstX, dstY,
155                 ctx->solid_color);
156   /* 2nd vertex */
157   setup_vertex0(ctx->vertices2[1], dstX + width, dstY,
158                 ctx->solid_color);
159   /* 3rd vertex */
160   setup_vertex0(ctx->vertices2[2], dstX + width, dstY + height,
161                 ctx->solid_color);
162   /* 4th vertex */
163   setup_vertex0(ctx->vertices2[3], dstX, dstY + height,
164                 ctx->solid_color);
165
166   return pipe_user_buffer_create(ctx->pipe->screen,
167                                  ctx->vertices2,
168                                  sizeof(ctx->vertices2));
169}
170
171static INLINE void
172setup_vertex1(float vertex[2][4], float x, float y, float s, float t)
173{
174   vertex[0][0] = x;
175   vertex[0][1] = y;
176   vertex[0][2] = 0.f; /*z*/
177   vertex[0][3] = 1.f; /*w*/
178
179   vertex[1][0] = s;   /*s*/
180   vertex[1][1] = t;   /*t*/
181   vertex[1][2] = 0.f; /*r*/
182   vertex[1][3] = 1.f; /*q*/
183}
184
185static struct pipe_buffer *
186setup_vertex_data1(struct exa_context *ctx,
187                   int srcX, int srcY, int maskX, int maskY,
188                   int dstX, int dstY, int width, int height)
189{
190   float s0, t0, s1, t1;
191   struct pipe_texture *src = ctx->bound_textures[0];
192
193   s0 = srcX / src->width[0];
194   s1 = srcX + width / src->width[0];
195   t0 = srcY / src->height[0];
196   t1 = srcY + height / src->height[0];
197
198   /* 1st vertex */
199   setup_vertex1(ctx->vertices2[0], dstX, dstY,
200                 s0, t0);
201   /* 2nd vertex */
202   setup_vertex1(ctx->vertices2[1], dstX + width, dstY,
203                 s1, t0);
204   /* 3rd vertex */
205   setup_vertex1(ctx->vertices2[2], dstX + width, dstY + height,
206                 s1, t1);
207   /* 4th vertex */
208   setup_vertex1(ctx->vertices2[3], dstX, dstY + height,
209                 s0, t1);
210
211   return pipe_user_buffer_create(ctx->pipe->screen,
212                                  ctx->vertices2,
213                                  sizeof(ctx->vertices2));
214}
215
216static struct pipe_buffer *
217setup_vertex_data_tex(struct exa_context *ctx,
218                      float x0, float y0, float x1, float y1,
219                      float s0, float t0, float s1, float t1,
220                      float z)
221{
222   /* 1st vertex */
223   setup_vertex1(ctx->vertices2[0], x0, y0,
224                 s0, t0);
225   /* 2nd vertex */
226   setup_vertex1(ctx->vertices2[1], x1, y0,
227                 s1, t0);
228   /* 3rd vertex */
229   setup_vertex1(ctx->vertices2[2], x1, y1,
230                 s1, t1);
231   /* 4th vertex */
232   setup_vertex1(ctx->vertices2[3], x0, y1,
233                 s0, t1);
234
235   return pipe_user_buffer_create(ctx->pipe->screen,
236                                  ctx->vertices2,
237                                  sizeof(ctx->vertices2));
238}
239
240
241
242static INLINE void
243setup_vertex2(float vertex[3][4], float x, float y,
244              float s0, float t0, float s1, float t1)
245{
246   vertex[0][0] = x;
247   vertex[0][1] = y;
248   vertex[0][2] = 0.f; /*z*/
249   vertex[0][3] = 1.f; /*w*/
250
251   vertex[1][0] = s0;  /*s*/
252   vertex[1][1] = t0;  /*t*/
253   vertex[1][2] = 0.f; /*r*/
254   vertex[1][3] = 1.f; /*q*/
255
256   vertex[2][0] = s1;  /*s*/
257   vertex[2][1] = t1;  /*t*/
258   vertex[2][2] = 0.f; /*r*/
259   vertex[2][3] = 1.f; /*q*/
260}
261
262static struct pipe_buffer *
263setup_vertex_data2(struct exa_context *ctx,
264                   int srcX, int srcY, int maskX, int maskY,
265                   int dstX, int dstY, int width, int height)
266{
267   float st0[4], st1[4];
268   struct pipe_texture *src = ctx->bound_textures[0];
269   struct pipe_texture *mask = ctx->bound_textures[0];
270
271   st0[0] = srcX / src->width[0];
272   st0[1] = srcY / src->height[0];
273   st0[2] = srcX + width / src->width[0];
274   st0[3] = srcY + height / src->height[0];
275
276   st1[0] = maskX / mask->width[0];
277   st1[1] = maskY / mask->height[0];
278   st1[2] = maskX + width / mask->width[0];
279   st1[3] = maskY + height / mask->height[0];
280
281   /* 1st vertex */
282   setup_vertex2(ctx->vertices3[0], dstX, dstY,
283                 st0[0], st0[1], st1[0], st1[1]);
284   /* 2nd vertex */
285   setup_vertex2(ctx->vertices3[1], dstX + width, dstY,
286                 st0[2], st0[1], st1[2], st1[1]);
287   /* 3rd vertex */
288   setup_vertex2(ctx->vertices3[2], dstX + width, dstY + height,
289                 st0[2], st0[3], st1[2], st1[3]);
290   /* 4th vertex */
291   setup_vertex2(ctx->vertices3[3], dstX, dstY + height,
292                 st0[0], st0[3], st1[0], st1[3]);
293
294   return pipe_user_buffer_create(ctx->pipe->screen,
295                                  ctx->vertices3,
296                                  sizeof(ctx->vertices3));
297}
298
299boolean xorg_composite_accelerated(int op,
300                                   PicturePtr pSrcPicture,
301                                   PicturePtr pMaskPicture,
302                                   PicturePtr pDstPicture)
303{
304   unsigned i;
305   unsigned accel_ops_count =
306      sizeof(accelerated_ops)/sizeof(struct acceleration_info);
307
308
309   /*FIXME: currently accel is disabled */
310   return FALSE;
311
312   if (pSrcPicture) {
313      /* component alpha not supported */
314      if (pSrcPicture->componentAlpha)
315         return FALSE;
316      /* fills not supported */
317      if (pSrcPicture->pSourcePict)
318         return FALSE;
319   }
320
321   for (i = 0; i < accel_ops_count; ++i) {
322      if (op == accelerated_ops[i].op) {
323         if (pMaskPicture && !accelerated_ops[i].with_mask)
324            return FALSE;
325         return TRUE;
326      }
327   }
328   return FALSE;
329}
330
331static void
332bind_clip_state(struct exa_context *exa)
333{
334}
335
336static void
337bind_framebuffer_state(struct exa_context *exa, struct exa_pixmap_priv *pDst)
338{
339   unsigned i;
340   struct pipe_framebuffer_state state;
341   struct pipe_surface *surface = exa_gpu_surface(exa, pDst);
342   memset(&state, 0, sizeof(struct pipe_framebuffer_state));
343
344   state.width  = pDst->tex->width[0];
345   state.height = pDst->tex->height[0];
346
347   state.nr_cbufs = 1;
348   state.cbufs[0] = surface;
349   for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i)
350      state.cbufs[i] = 0;
351
352   /* currently we don't use depth/stencil */
353   state.zsbuf = 0;
354
355   cso_set_framebuffer(exa->cso, &state);
356
357   /* we do fire and forget for the framebuffer, this is the forget part */
358   pipe_surface_reference(&surface, NULL);
359}
360
361enum AxisOrientation {
362   Y0_BOTTOM,
363   Y0_TOP
364};
365
366static void
367set_viewport(struct exa_context *exa, int width, int height,
368             enum AxisOrientation orientation)
369{
370   struct pipe_viewport_state viewport;
371   float y_scale = (orientation == Y0_BOTTOM) ? -2.f : 2.f;
372
373   viewport.scale[0] =  width / 2.f;
374   viewport.scale[1] =  height / y_scale;
375   viewport.scale[2] =  1.0;
376   viewport.scale[3] =  1.0;
377   viewport.translate[0] = width / 2.f;
378   viewport.translate[1] = height / 2.f;
379   viewport.translate[2] = 0.0;
380   viewport.translate[3] = 0.0;
381
382   cso_set_viewport(exa->cso, &viewport);
383}
384
385static void
386bind_viewport_state(struct exa_context *exa, struct exa_pixmap_priv *pDst)
387{
388   int width = pDst->tex->width[0];
389   int height = pDst->tex->height[0];
390
391   /*debug_printf("Bind viewport (%d, %d)\n", width, height);*/
392
393   set_viewport(exa, width, height, Y0_TOP);
394}
395
396static void
397bind_blend_state(struct exa_context *exa, int op,
398                 PicturePtr pSrcPicture, PicturePtr pMaskPicture)
399{
400   boolean component_alpha = (pSrcPicture) ?
401                             pSrcPicture->componentAlpha : FALSE;
402   struct xorg_composite_blend blend_opt;
403   struct pipe_blend_state blend;
404
405   if (component_alpha) {
406      op = PictOpOver;
407   }
408   blend_opt = blend_for_op(op);
409
410   memset(&blend, 0, sizeof(struct pipe_blend_state));
411   blend.blend_enable = 1;
412   blend.colormask |= PIPE_MASK_R;
413   blend.colormask |= PIPE_MASK_G;
414   blend.colormask |= PIPE_MASK_B;
415   blend.colormask |= PIPE_MASK_A;
416
417   blend.rgb_src_factor   = blend_opt.rgb_src_factor;
418   blend.alpha_src_factor = blend_opt.alpha_src_factor;
419   blend.rgb_dst_factor   = blend_opt.rgb_dst_factor;
420   blend.alpha_dst_factor = blend_opt.alpha_dst_factor;
421
422   cso_set_blend(exa->cso, &blend);
423}
424
425static void
426bind_rasterizer_state(struct exa_context *exa)
427{
428   struct pipe_rasterizer_state raster;
429   memset(&raster, 0, sizeof(struct pipe_rasterizer_state));
430   raster.gl_rasterization_rules = 1;
431   cso_set_rasterizer(exa->cso, &raster);
432}
433
434static void
435bind_shaders(struct exa_context *exa, int op,
436             PicturePtr pSrcPicture, PicturePtr pMaskPicture)
437{
438   unsigned vs_traits = 0, fs_traits = 0;
439   struct xorg_shader shader;
440
441   exa->has_solid_color = FALSE;
442
443   if (pSrcPicture) {
444      if (pSrcPicture->pSourcePict) {
445         if (pSrcPicture->pSourcePict->type == SourcePictTypeSolidFill) {
446            fs_traits |= FS_SOLID_FILL;
447            vs_traits |= VS_SOLID_FILL;
448            render_pixel_to_float4(pSrcPicture->pFormat,
449                                   pSrcPicture->pSourcePict->solidFill.color,
450                                   exa->solid_color);
451            exa->has_solid_color = TRUE;
452         } else {
453            debug_assert("!gradients not supported");
454         }
455      } else {
456         fs_traits |= FS_COMPOSITE;
457         vs_traits |= VS_COMPOSITE;
458      }
459   }
460
461   if (pMaskPicture) {
462      vs_traits |= VS_MASK;
463      fs_traits |= FS_MASK;
464   }
465
466   shader = xorg_shaders_get(exa->shaders, vs_traits, fs_traits);
467   cso_set_vertex_shader_handle(exa->cso, shader.vs);
468   cso_set_fragment_shader_handle(exa->cso, shader.fs);
469}
470
471
472static void
473bind_samplers(struct exa_context *exa, int op,
474              PicturePtr pSrcPicture, PicturePtr pMaskPicture,
475              PicturePtr pDstPicture,
476              struct exa_pixmap_priv *pSrc,
477              struct exa_pixmap_priv *pMask,
478              struct exa_pixmap_priv *pDst)
479{
480   struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS];
481   struct pipe_sampler_state src_sampler, mask_sampler;
482
483   exa->num_bound_samplers = 0;
484
485   memset(&src_sampler, 0, sizeof(struct pipe_sampler_state));
486   memset(&mask_sampler, 0, sizeof(struct pipe_sampler_state));
487
488   if (pSrcPicture && pSrc) {
489      unsigned src_wrap = render_repeat_to_gallium(
490         pSrcPicture->repeatType);
491      src_sampler.wrap_s = src_wrap;
492      src_sampler.wrap_t = src_wrap;
493      src_sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
494      src_sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
495      src_sampler.normalized_coords = 1;
496      samplers[0] = &src_sampler;
497      exa->bound_textures[0] = pSrc->tex;
498      ++exa->num_bound_samplers;
499   }
500
501   if (pMaskPicture && pMask) {
502      unsigned mask_wrap = render_repeat_to_gallium(
503         pMaskPicture->repeatType);
504      mask_sampler.wrap_s = mask_wrap;
505      mask_sampler.wrap_t = mask_wrap;
506      mask_sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
507      mask_sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
508      mask_sampler.normalized_coords = 1;
509      samplers[1] = &mask_sampler;
510      exa->bound_textures[1] = pMask->tex;
511      ++exa->num_bound_samplers;
512   }
513
514   cso_set_samplers(exa->cso, exa->num_bound_samplers,
515                    (const struct pipe_sampler_state **)samplers);
516   cso_set_sampler_textures(exa->cso, exa->num_bound_samplers,
517                            exa->bound_textures);
518}
519
520static void
521setup_vs_constant_buffer(struct exa_context *exa,
522                         int width, int height)
523{
524   const int param_bytes = 8 * sizeof(float);
525   float vs_consts[8] = {
526      2.f/width, 2.f/height, 1, 1,
527      -1, -1, 0, 0
528   };
529   struct pipe_constant_buffer *cbuf = &exa->vs_const_buffer;
530
531   pipe_buffer_reference(&cbuf->buffer, NULL);
532   cbuf->buffer = pipe_buffer_create(exa->pipe->screen, 16,
533                                     PIPE_BUFFER_USAGE_CONSTANT,
534                                     param_bytes);
535
536   if (cbuf->buffer) {
537      pipe_buffer_write(exa->pipe->screen, cbuf->buffer,
538                        0, param_bytes, vs_consts);
539   }
540   exa->pipe->set_constant_buffer(exa->pipe, PIPE_SHADER_VERTEX, 0, cbuf);
541}
542
543
544static void
545setup_fs_constant_buffer(struct exa_context *exa)
546{
547   const int param_bytes = 4 * sizeof(float);
548   float fs_consts[8] = {
549      0, 0, 0, 1,
550   };
551   struct pipe_constant_buffer *cbuf = &exa->fs_const_buffer;
552
553   pipe_buffer_reference(&cbuf->buffer, NULL);
554   cbuf->buffer = pipe_buffer_create(exa->pipe->screen, 16,
555                                     PIPE_BUFFER_USAGE_CONSTANT,
556                                     param_bytes);
557
558   if (cbuf->buffer) {
559      pipe_buffer_write(exa->pipe->screen, cbuf->buffer,
560                        0, param_bytes, fs_consts);
561   }
562   exa->pipe->set_constant_buffer(exa->pipe, PIPE_SHADER_FRAGMENT, 0, cbuf);
563}
564
565static void
566setup_constant_buffers(struct exa_context *exa, struct exa_pixmap_priv *pDst)
567{
568   int width = pDst->tex->width[0];
569   int height = pDst->tex->height[0];
570
571   setup_vs_constant_buffer(exa, width, height);
572   setup_fs_constant_buffer(exa);
573}
574
575boolean xorg_composite_bind_state(struct exa_context *exa,
576                                  int op,
577                                  PicturePtr pSrcPicture,
578                                  PicturePtr pMaskPicture,
579                                  PicturePtr pDstPicture,
580                                  struct exa_pixmap_priv *pSrc,
581                                  struct exa_pixmap_priv *pMask,
582                                  struct exa_pixmap_priv *pDst)
583{
584   bind_framebuffer_state(exa, pDst);
585   bind_viewport_state(exa, pDst);
586   bind_blend_state(exa, op, pSrcPicture, pMaskPicture);
587   bind_rasterizer_state(exa);
588   bind_shaders(exa, op, pSrcPicture, pMaskPicture);
589   bind_samplers(exa, op, pSrcPicture, pMaskPicture,
590                 pDstPicture, pSrc, pMask, pDst);
591   bind_clip_state(exa);
592   setup_constant_buffers(exa, pDst);
593
594   return FALSE;
595}
596
597void xorg_composite(struct exa_context *exa,
598                    struct exa_pixmap_priv *dst,
599                    int srcX, int srcY, int maskX, int maskY,
600                    int dstX, int dstY, int width, int height)
601{
602   struct pipe_context *pipe = exa->pipe;
603   struct pipe_buffer *buf = 0;
604
605   if (exa->num_bound_samplers == 0 ) { /* solid fill */
606      buf = setup_vertex_data0(exa,
607                               srcX, srcY, maskX, maskY,
608                               dstX, dstY, width, height);
609   } else if (exa->num_bound_samplers == 1 ) /* src */
610      buf = setup_vertex_data1(exa,
611                               srcX, srcY, maskX, maskY,
612                               dstX, dstY, width, height);
613   else if (exa->num_bound_samplers == 2) /* src + mask */
614      buf = setup_vertex_data2(exa,
615                               srcX, srcY, maskX, maskY,
616                               dstX, dstY, width, height);
617   else if (exa->num_bound_samplers == 3) { /* src + mask + dst */
618      debug_assert(!"src/mask/dst not handled right now");
619#if 0
620      buf = setup_vertex_data2(exa,
621                               srcX, srcY, maskX, maskY,
622                               dstX, dstY, width, height);
623#endif
624   }
625
626   if (buf) {
627      int num_attribs = 1; /*pos*/
628      num_attribs += exa->num_bound_samplers;
629      if (exa->has_solid_color)
630         ++num_attribs;
631
632      util_draw_vertex_buffer(pipe, buf, 0,
633                              PIPE_PRIM_TRIANGLE_FAN,
634                              4,  /* verts */
635                              num_attribs); /* attribs/vert */
636
637      pipe_buffer_reference(&buf, NULL);
638   }
639}
640
641boolean xorg_solid_bind_state(struct exa_context *exa,
642                              struct exa_pixmap_priv *pixmap,
643                              Pixel fg)
644{
645   unsigned vs_traits, fs_traits;
646   struct xorg_shader shader;
647
648   pixel_to_float4(fg, exa->solid_color);
649   exa->has_solid_color = TRUE;
650
651   exa->solid_color[3] = 1.f;
652
653#if 0
654   debug_printf("Color Pixel=(%d, %d, %d, %d), RGBA=(%f, %f, %f, %f)\n",
655                (fg >> 24) & 0xff, (fg >> 16) & 0xff,
656                (fg >> 8) & 0xff,  (fg >> 0) & 0xff,
657                exa->solid_color[0], exa->solid_color[1],
658                exa->solid_color[2], exa->solid_color[3]);
659#endif
660
661   vs_traits = VS_SOLID_FILL;
662   fs_traits = FS_SOLID_FILL;
663
664   bind_framebuffer_state(exa, pixmap);
665   bind_viewport_state(exa, pixmap);
666   bind_rasterizer_state(exa);
667   bind_blend_state(exa, PictOpSrc, NULL, NULL);
668   setup_constant_buffers(exa, pixmap);
669   bind_clip_state(exa);
670
671   shader = xorg_shaders_get(exa->shaders, vs_traits, fs_traits);
672   cso_set_vertex_shader_handle(exa->cso, shader.vs);
673   cso_set_fragment_shader_handle(exa->cso, shader.fs);
674
675   return TRUE;
676}
677
678void xorg_solid(struct exa_context *exa,
679                struct exa_pixmap_priv *pixmap,
680                int x0, int y0, int x1, int y1)
681{
682   struct pipe_context *pipe = exa->pipe;
683   struct pipe_buffer *buf = 0;
684
685   /* 1st vertex */
686   setup_vertex0(exa->vertices2[0], x0, y0,
687                 exa->solid_color);
688   /* 2nd vertex */
689   setup_vertex0(exa->vertices2[1], x1, y0,
690                 exa->solid_color);
691   /* 3rd vertex */
692   setup_vertex0(exa->vertices2[2], x1, y1,
693                 exa->solid_color);
694   /* 4th vertex */
695   setup_vertex0(exa->vertices2[3], x0, y1,
696                 exa->solid_color);
697
698   buf = pipe_user_buffer_create(exa->pipe->screen,
699                                 exa->vertices2,
700                                 sizeof(exa->vertices2));
701
702
703   if (buf) {
704      util_draw_vertex_buffer(pipe, buf, 0,
705                              PIPE_PRIM_TRIANGLE_FAN,
706                              4,  /* verts */
707                              2); /* attribs/vert */
708
709      pipe_buffer_reference(&buf, NULL);
710   }
711}
712
713
714static INLINE void shift_rectx(float coords[4],
715                               const float *bounds,
716                               const float shift)
717{
718   coords[0] += shift;
719   coords[2] -= shift;
720   if (bounds) {
721      coords[2] = MIN2(coords[2], bounds[2]);
722      /* bound x/y + width/height */
723      if ((coords[0] + coords[2]) > (bounds[0] + bounds[2])) {
724         coords[2] = (bounds[0] + bounds[2]) - coords[0];
725      }
726   }
727}
728
729static INLINE void shift_recty(float coords[4],
730                               const float *bounds,
731                               const float shift)
732{
733   coords[1] += shift;
734   coords[3] -= shift;
735   if (bounds) {
736      coords[3] = MIN2(coords[3], bounds[3]);
737      if ((coords[1] + coords[3]) > (bounds[1] + bounds[3])) {
738         coords[3] = (bounds[1] + bounds[3]) - coords[1];
739      }
740   }
741}
742
743static INLINE void bound_rect(float coords[4],
744                              const float bounds[4],
745                              float shift[4])
746{
747   /* if outside the bounds */
748   if (coords[0] > (bounds[0] + bounds[2]) ||
749       coords[1] > (bounds[1] + bounds[3]) ||
750       (coords[0] + coords[2]) < bounds[0] ||
751       (coords[1] + coords[3]) < bounds[1]) {
752      coords[0] = 0.f;
753      coords[1] = 0.f;
754      coords[2] = 0.f;
755      coords[3] = 0.f;
756      shift[0] = 0.f;
757      shift[1] = 0.f;
758      return;
759   }
760
761   /* bound x */
762   if (coords[0] < bounds[0]) {
763      shift[0] = bounds[0] - coords[0];
764      coords[2] -= shift[0];
765      coords[0] = bounds[0];
766   } else
767      shift[0] = 0.f;
768
769   /* bound y */
770   if (coords[1] < bounds[1]) {
771      shift[1] = bounds[1] - coords[1];
772      coords[3] -= shift[1];
773      coords[1] = bounds[1];
774   } else
775      shift[1] = 0.f;
776
777   shift[2] = bounds[2] - coords[2];
778   shift[3] = bounds[3] - coords[3];
779   /* bound width/height */
780   coords[2] = MIN2(coords[2], bounds[2]);
781   coords[3] = MIN2(coords[3], bounds[3]);
782
783   /* bound x/y + width/height */
784   if ((coords[0] + coords[2]) > (bounds[0] + bounds[2])) {
785      coords[2] = (bounds[0] + bounds[2]) - coords[0];
786   }
787   if ((coords[1] + coords[3]) > (bounds[1] + bounds[3])) {
788      coords[3] = (bounds[1] + bounds[3]) - coords[1];
789   }
790
791   /* if outside the bounds */
792   if ((coords[0] + coords[2]) < bounds[0] ||
793       (coords[1] + coords[3]) < bounds[1]) {
794      coords[0] = 0.f;
795      coords[1] = 0.f;
796      coords[2] = 0.f;
797      coords[3] = 0.f;
798      return;
799   }
800}
801
802static INLINE void sync_size(float *src_loc, float *dst_loc)
803{
804   src_loc[2] = MIN2(src_loc[2], dst_loc[2]);
805   src_loc[3] = MIN2(src_loc[3], dst_loc[3]);
806   dst_loc[2] = src_loc[2];
807   dst_loc[3] = src_loc[3];
808}
809
810
811static void renderer_copy_texture(struct exa_context *exa,
812                                  struct pipe_texture *src,
813                                  float sx1, float sy1,
814                                  float sx2, float sy2,
815                                  struct pipe_texture *dst,
816                                  float dx1, float dy1,
817                                  float dx2, float dy2)
818{
819   struct pipe_context *pipe = exa->pipe;
820   struct pipe_screen *screen = pipe->screen;
821   struct pipe_buffer *buf;
822   struct pipe_surface *dst_surf = screen->get_tex_surface(
823      screen, dst, 0, 0, 0,
824      PIPE_BUFFER_USAGE_GPU_WRITE);
825   struct pipe_framebuffer_state fb;
826   float s0, t0, s1, t1;
827   struct xorg_shader shader;
828
829   assert(src->width[0] != 0);
830   assert(src->height[0] != 0);
831   assert(dst->width[0] != 0);
832   assert(dst->height[0] != 0);
833
834#if 1
835   s0 = sx1 / src->width[0];
836   s1 = sx2 / src->width[0];
837   t0 = sy1 / src->height[0];
838   t1 = sy2 / src->height[0];
839#else
840   s0 = 0;
841   s1 = 1;
842   t0 = 0;
843   t1 = 1;
844#endif
845
846#if 1
847   debug_printf("copy texture src=[%f, %f, %f, %f], dst=[%f, %f, %f, %f], tex=[%f, %f, %f, %f]\n",
848                sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2,
849                s0, t0, s1, t1);
850#endif
851
852   assert(screen->is_format_supported(screen, dst_surf->format,
853                                      PIPE_TEXTURE_2D,
854                                      PIPE_TEXTURE_USAGE_RENDER_TARGET,
855                                      0));
856
857   /* save state (restored below) */
858   cso_save_blend(exa->cso);
859   cso_save_samplers(exa->cso);
860   cso_save_sampler_textures(exa->cso);
861   cso_save_framebuffer(exa->cso);
862   cso_save_fragment_shader(exa->cso);
863   cso_save_vertex_shader(exa->cso);
864
865   cso_save_viewport(exa->cso);
866
867
868   /* set misc state we care about */
869   {
870      struct pipe_blend_state blend;
871      memset(&blend, 0, sizeof(blend));
872      blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE;
873      blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE;
874      blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
875      blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
876      blend.colormask = PIPE_MASK_RGBA;
877      cso_set_blend(exa->cso, &blend);
878   }
879
880   /* sampler */
881   {
882      struct pipe_sampler_state sampler;
883      memset(&sampler, 0, sizeof(sampler));
884      sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
885      sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
886      sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
887      sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
888      sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
889      sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
890      sampler.normalized_coords = 1;
891      cso_single_sampler(exa->cso, 0, &sampler);
892      cso_single_sampler_done(exa->cso);
893   }
894
895   set_viewport(exa, dst_surf->width, dst_surf->height, Y0_TOP);
896
897   /* texture */
898   cso_set_sampler_textures(exa->cso, 1, &src);
899
900   /* shaders */
901   shader = xorg_shaders_get(exa->shaders,
902                             VS_COMPOSITE,
903                             FS_COMPOSITE);
904   cso_set_vertex_shader_handle(exa->cso, shader.vs);
905   cso_set_fragment_shader_handle(exa->cso, shader.fs);
906
907   /* drawing dest */
908   memset(&fb, 0, sizeof(fb));
909   fb.width = dst_surf->width;
910   fb.height = dst_surf->height;
911   fb.nr_cbufs = 1;
912   fb.cbufs[0] = dst_surf;
913   {
914      int i;
915      for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i)
916         fb.cbufs[i] = 0;
917   }
918   cso_set_framebuffer(exa->cso, &fb);
919   setup_vs_constant_buffer(exa, fb.width, fb.height);
920   setup_fs_constant_buffer(exa);
921
922   /* draw quad */
923   buf = setup_vertex_data_tex(exa,
924                               dx1, dy1,
925                               dx2, dy2,
926                               s0, t0, s1, t1,
927                               0.0f);
928
929   if (buf) {
930      util_draw_vertex_buffer(exa->pipe, buf, 0,
931                              PIPE_PRIM_TRIANGLE_FAN,
932                              4,  /* verts */
933                              2); /* attribs/vert */
934
935      pipe_buffer_reference(&buf, NULL);
936   }
937
938   /* restore state we changed */
939   cso_restore_blend(exa->cso);
940   cso_restore_samplers(exa->cso);
941   cso_restore_sampler_textures(exa->cso);
942   cso_restore_framebuffer(exa->cso);
943   cso_restore_vertex_shader(exa->cso);
944   cso_restore_fragment_shader(exa->cso);
945   cso_restore_viewport(exa->cso);
946
947   pipe_surface_reference(&dst_surf, NULL);
948}
949
950
951static struct pipe_texture *
952create_sampler_texture(struct exa_context *ctx,
953                       struct pipe_texture *src)
954{
955   enum pipe_format format;
956   struct pipe_context *pipe = ctx->pipe;
957   struct pipe_screen *screen = pipe->screen;
958   struct pipe_texture *pt;
959   struct pipe_texture templ;
960
961   pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
962
963   /* the coming in texture should already have that invariance */
964   debug_assert(screen->is_format_supported(screen, src->format,
965                                            PIPE_TEXTURE_2D,
966                                            PIPE_TEXTURE_USAGE_SAMPLER, 0));
967
968   format = src->format;
969
970   memset(&templ, 0, sizeof(templ));
971   templ.target = PIPE_TEXTURE_2D;
972   templ.format = format;
973   templ.last_level = 0;
974   templ.width[0] = src->width[0];
975   templ.height[0] = src->height[0];
976   templ.depth[0] = 1;
977   pf_get_block(format, &templ.block);
978   templ.tex_usage = PIPE_TEXTURE_USAGE_SAMPLER;
979
980   pt = screen->texture_create(screen, &templ);
981
982   debug_assert(!pt || pipe_is_referenced(&pt->reference));
983
984   if (!pt)
985      return NULL;
986
987   {
988      /* copy source framebuffer surface into texture */
989      struct pipe_surface *ps_read = screen->get_tex_surface(
990         screen, src, 0, 0, 0, PIPE_BUFFER_USAGE_GPU_READ);
991      struct pipe_surface *ps_tex = screen->get_tex_surface(
992         screen, pt, 0, 0, 0, PIPE_BUFFER_USAGE_GPU_WRITE );
993      pipe->surface_copy(pipe,
994			 ps_tex, /* dest */
995			 0, 0, /* destx/y */
996			 ps_read,
997			 0, 0, src->width[0], src->height[0]);
998      pipe_surface_reference(&ps_read, NULL);
999      pipe_surface_reference(&ps_tex, NULL);
1000   }
1001
1002   return pt;
1003}
1004
1005void xorg_copy_pixmap(struct exa_context *ctx,
1006                      struct exa_pixmap_priv *dst_priv, int dx, int dy,
1007                      struct exa_pixmap_priv *src_priv, int sx, int sy,
1008                      int width, int height)
1009{
1010   float dst_loc[4], src_loc[4];
1011   float dst_bounds[4], src_bounds[4];
1012   float src_shift[4], dst_shift[4], shift[4];
1013   struct pipe_texture *dst = dst_priv->tex;
1014   struct pipe_texture *src = src_priv->tex;
1015
1016   xorg_exa_finish(ctx);
1017
1018   dst_loc[0] = dx;
1019   dst_loc[1] = dy;
1020   dst_loc[2] = width;
1021   dst_loc[3] = height;
1022   dst_bounds[0] = 0.f;
1023   dst_bounds[1] = 0.f;
1024   dst_bounds[2] = dst->width[0];
1025   dst_bounds[3] = dst->height[0];
1026
1027   src_loc[0] = sx;
1028   src_loc[1] = sy;
1029   src_loc[2] = width;
1030   src_loc[3] = height;
1031   src_bounds[0] = 0.f;
1032   src_bounds[1] = 0.f;
1033   src_bounds[2] = src->width[0];
1034   src_bounds[3] = src->height[0];
1035
1036   bound_rect(src_loc, src_bounds, src_shift);
1037   bound_rect(dst_loc, dst_bounds, dst_shift);
1038   shift[0] = src_shift[0] - dst_shift[0];
1039   shift[1] = src_shift[1] - dst_shift[1];
1040
1041   if (shift[0] < 0)
1042      shift_rectx(src_loc, src_bounds, -shift[0]);
1043   else
1044      shift_rectx(dst_loc, dst_bounds, shift[0]);
1045
1046   if (shift[1] < 0)
1047      shift_recty(src_loc, src_bounds, -shift[1]);
1048   else
1049      shift_recty(dst_loc, dst_bounds, shift[1]);
1050
1051   sync_size(src_loc, dst_loc);
1052
1053   if (src_loc[2] >= 0 && src_loc[3] >= 0 &&
1054       dst_loc[2] >= 0 && dst_loc[3] >= 0) {
1055      struct pipe_texture *temp_src = src;
1056
1057      if (src == dst)
1058         temp_src = create_sampler_texture(ctx, src);
1059
1060      renderer_copy_texture(ctx,
1061                            temp_src,
1062                            src_loc[0],
1063                            src_loc[1],
1064                            src_loc[0] + src_loc[2],
1065                            src_loc[1] + src_loc[3],
1066                            dst,
1067                            dst_loc[0],
1068                            dst_loc[1],
1069                            dst_loc[0] + dst_loc[2],
1070                            dst_loc[1] + dst_loc[3]);
1071
1072      if (src == dst)
1073         pipe_texture_reference(&temp_src, NULL);
1074   }
1075}
1076
1077