xorg_composite.c revision 80965fca743c3101af731080cb81dec705cd931b
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   if (pSrcPicture) {
309      /* component alpha not supported */
310      if (pSrcPicture->componentAlpha)
311         return FALSE;
312   }
313
314   for (i = 0; i < accel_ops_count; ++i) {
315      if (op == accelerated_ops[i].op) {
316         if (pMaskPicture && !accelerated_ops[i].with_mask)
317            return FALSE;
318         return TRUE;
319      }
320   }
321   return FALSE;
322}
323
324static void
325bind_clip_state(struct exa_context *exa)
326{
327}
328
329static void
330bind_framebuffer_state(struct exa_context *exa, struct exa_pixmap_priv *pDst)
331{
332   unsigned i;
333   struct pipe_framebuffer_state state;
334   struct pipe_surface *surface = exa_gpu_surface(exa, pDst);
335   memset(&state, 0, sizeof(struct pipe_framebuffer_state));
336
337   state.width  = pDst->tex->width[0];
338   state.height = pDst->tex->height[0];
339
340   state.nr_cbufs = 1;
341   state.cbufs[0] = surface;
342   for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i)
343      state.cbufs[i] = 0;
344
345   /* currently we don't use depth/stencil */
346   state.zsbuf = 0;
347
348   cso_set_framebuffer(exa->cso, &state);
349
350   /* we do fire and forget for the framebuffer, this is the forget part */
351   pipe_surface_reference(&surface, NULL);
352}
353
354enum AxisOrientation {
355   Y0_BOTTOM,
356   Y0_TOP
357};
358
359static void
360set_viewport(struct exa_context *exa, int width, int height,
361             enum AxisOrientation orientation)
362{
363   struct pipe_viewport_state viewport;
364   float y_scale = (orientation == Y0_BOTTOM) ? -2.f : 2.f;
365
366   viewport.scale[0] =  width / 2.f;
367   viewport.scale[1] =  height / y_scale;
368   viewport.scale[2] =  1.0;
369   viewport.scale[3] =  1.0;
370   viewport.translate[0] = width / 2.f;
371   viewport.translate[1] = height / 2.f;
372   viewport.translate[2] = 0.0;
373   viewport.translate[3] = 0.0;
374
375   cso_set_viewport(exa->cso, &viewport);
376}
377
378static void
379bind_viewport_state(struct exa_context *exa, struct exa_pixmap_priv *pDst)
380{
381   int width = pDst->tex->width[0];
382   int height = pDst->tex->height[0];
383
384   /*debug_printf("Bind viewport (%d, %d)\n", width, height);*/
385
386   set_viewport(exa, width, height, Y0_TOP);
387}
388
389static void
390bind_blend_state(struct exa_context *exa, int op,
391                 PicturePtr pSrcPicture, PicturePtr pMaskPicture)
392{
393   boolean component_alpha = (pSrcPicture) ?
394                             pSrcPicture->componentAlpha : FALSE;
395   struct xorg_composite_blend blend_opt;
396   struct pipe_blend_state blend;
397
398   if (component_alpha) {
399      op = PictOpOver;
400   }
401   blend_opt = blend_for_op(op);
402
403   memset(&blend, 0, sizeof(struct pipe_blend_state));
404   blend.blend_enable = 1;
405   blend.colormask |= PIPE_MASK_R;
406   blend.colormask |= PIPE_MASK_G;
407   blend.colormask |= PIPE_MASK_B;
408   blend.colormask |= PIPE_MASK_A;
409
410   blend.rgb_src_factor   = blend_opt.rgb_src_factor;
411   blend.alpha_src_factor = blend_opt.alpha_src_factor;
412   blend.rgb_dst_factor   = blend_opt.rgb_dst_factor;
413   blend.alpha_dst_factor = blend_opt.alpha_dst_factor;
414
415   cso_set_blend(exa->cso, &blend);
416}
417
418static void
419bind_rasterizer_state(struct exa_context *exa)
420{
421   struct pipe_rasterizer_state raster;
422   memset(&raster, 0, sizeof(struct pipe_rasterizer_state));
423   raster.gl_rasterization_rules = 1;
424   cso_set_rasterizer(exa->cso, &raster);
425}
426
427static void
428bind_shaders(struct exa_context *exa, int op,
429             PicturePtr pSrcPicture, PicturePtr pMaskPicture)
430{
431   unsigned vs_traits = 0, fs_traits = 0;
432   struct xorg_shader shader;
433
434   exa->has_solid_color = FALSE;
435
436   if (pSrcPicture) {
437      if (pSrcPicture->pSourcePict) {
438         if (pSrcPicture->pSourcePict->type == SourcePictTypeSolidFill) {
439            fs_traits |= FS_SOLID_FILL;
440            vs_traits |= VS_SOLID_FILL;
441            render_pixel_to_float4(pSrcPicture->pFormat,
442                                   pSrcPicture->pSourcePict->solidFill.color,
443                                   exa->solid_color);
444            exa->has_solid_color = TRUE;
445         } else {
446            debug_assert("!gradients not supported");
447         }
448      } else {
449         fs_traits |= FS_COMPOSITE;
450         vs_traits |= VS_COMPOSITE;
451      }
452   }
453
454   if (pMaskPicture) {
455      vs_traits |= VS_MASK;
456      fs_traits |= FS_MASK;
457   }
458
459   shader = xorg_shaders_get(exa->shaders, vs_traits, fs_traits);
460   cso_set_vertex_shader_handle(exa->cso, shader.vs);
461   cso_set_fragment_shader_handle(exa->cso, shader.fs);
462}
463
464
465static void
466bind_samplers(struct exa_context *exa, int op,
467              PicturePtr pSrcPicture, PicturePtr pMaskPicture,
468              PicturePtr pDstPicture,
469              struct exa_pixmap_priv *pSrc,
470              struct exa_pixmap_priv *pMask,
471              struct exa_pixmap_priv *pDst)
472{
473   struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS];
474   struct pipe_sampler_state src_sampler, mask_sampler;
475
476   exa->num_bound_samplers = 0;
477
478   memset(&src_sampler, 0, sizeof(struct pipe_sampler_state));
479   memset(&mask_sampler, 0, sizeof(struct pipe_sampler_state));
480
481   if (pSrcPicture && pSrc) {
482      unsigned src_wrap = render_repeat_to_gallium(
483         pSrcPicture->repeatType);
484      src_sampler.wrap_s = src_wrap;
485      src_sampler.wrap_t = src_wrap;
486      src_sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
487      src_sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
488      src_sampler.normalized_coords = 1;
489      samplers[0] = &src_sampler;
490      exa->bound_textures[0] = pSrc->tex;
491      ++exa->num_bound_samplers;
492   }
493
494   if (pMaskPicture && pMask) {
495      unsigned mask_wrap = render_repeat_to_gallium(
496         pMaskPicture->repeatType);
497      mask_sampler.wrap_s = mask_wrap;
498      mask_sampler.wrap_t = mask_wrap;
499      mask_sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
500      mask_sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
501      mask_sampler.normalized_coords = 1;
502      samplers[1] = &mask_sampler;
503      exa->bound_textures[1] = pMask->tex;
504      ++exa->num_bound_samplers;
505   }
506
507   cso_set_samplers(exa->cso, exa->num_bound_samplers,
508                    (const struct pipe_sampler_state **)samplers);
509   cso_set_sampler_textures(exa->cso, exa->num_bound_samplers,
510                            exa->bound_textures);
511}
512
513static void
514setup_vs_constant_buffer(struct exa_context *exa,
515                         int width, int height)
516{
517   const int param_bytes = 8 * sizeof(float);
518   float vs_consts[8] = {
519      2.f/width, 2.f/height, 1, 1,
520      -1, -1, 0, 0
521   };
522   struct pipe_constant_buffer *cbuf = &exa->vs_const_buffer;
523
524   pipe_buffer_reference(&cbuf->buffer, NULL);
525   cbuf->buffer = pipe_buffer_create(exa->pipe->screen, 16,
526                                     PIPE_BUFFER_USAGE_CONSTANT,
527                                     param_bytes);
528
529   if (cbuf->buffer) {
530      pipe_buffer_write(exa->pipe->screen, cbuf->buffer,
531                        0, param_bytes, vs_consts);
532   }
533   exa->pipe->set_constant_buffer(exa->pipe, PIPE_SHADER_VERTEX, 0, cbuf);
534}
535
536
537static void
538setup_fs_constant_buffer(struct exa_context *exa)
539{
540   const int param_bytes = 4 * sizeof(float);
541   float fs_consts[8] = {
542      0, 0, 0, 1,
543   };
544   struct pipe_constant_buffer *cbuf = &exa->fs_const_buffer;
545
546   pipe_buffer_reference(&cbuf->buffer, NULL);
547   cbuf->buffer = pipe_buffer_create(exa->pipe->screen, 16,
548                                     PIPE_BUFFER_USAGE_CONSTANT,
549                                     param_bytes);
550
551   if (cbuf->buffer) {
552      pipe_buffer_write(exa->pipe->screen, cbuf->buffer,
553                        0, param_bytes, fs_consts);
554   }
555   exa->pipe->set_constant_buffer(exa->pipe, PIPE_SHADER_FRAGMENT, 0, cbuf);
556}
557
558static void
559setup_constant_buffers(struct exa_context *exa, struct exa_pixmap_priv *pDst)
560{
561   int width = pDst->tex->width[0];
562   int height = pDst->tex->height[0];
563
564   setup_vs_constant_buffer(exa, width, height);
565   setup_fs_constant_buffer(exa);
566}
567
568boolean xorg_composite_bind_state(struct exa_context *exa,
569                                  int op,
570                                  PicturePtr pSrcPicture,
571                                  PicturePtr pMaskPicture,
572                                  PicturePtr pDstPicture,
573                                  struct exa_pixmap_priv *pSrc,
574                                  struct exa_pixmap_priv *pMask,
575                                  struct exa_pixmap_priv *pDst)
576{
577   bind_framebuffer_state(exa, pDst);
578   bind_viewport_state(exa, pDst);
579   bind_blend_state(exa, op, pSrcPicture, pMaskPicture);
580   bind_rasterizer_state(exa);
581   bind_shaders(exa, op, pSrcPicture, pMaskPicture);
582   bind_samplers(exa, op, pSrcPicture, pMaskPicture,
583                 pDstPicture, pSrc, pMask, pDst);
584   bind_clip_state(exa);
585   setup_constant_buffers(exa, pDst);
586
587   return FALSE;
588}
589
590void xorg_composite(struct exa_context *exa,
591                    struct exa_pixmap_priv *dst,
592                    int srcX, int srcY, int maskX, int maskY,
593                    int dstX, int dstY, int width, int height)
594{
595   struct pipe_context *pipe = exa->pipe;
596   struct pipe_buffer *buf = 0;
597
598   if (exa->num_bound_samplers == 0 ) { /* solid fill */
599      buf = setup_vertex_data0(exa,
600                               srcX, srcY, maskX, maskY,
601                               dstX, dstY, width, height);
602   } else if (exa->num_bound_samplers == 1 ) /* src */
603      buf = setup_vertex_data1(exa,
604                               srcX, srcY, maskX, maskY,
605                               dstX, dstY, width, height);
606   else if (exa->num_bound_samplers == 2) /* src + mask */
607      buf = setup_vertex_data2(exa,
608                               srcX, srcY, maskX, maskY,
609                               dstX, dstY, width, height);
610   else if (exa->num_bound_samplers == 3) { /* src + mask + dst */
611      debug_assert(!"src/mask/dst not handled right now");
612#if 0
613      buf = setup_vertex_data2(exa,
614                               srcX, srcY, maskX, maskY,
615                               dstX, dstY, width, height);
616#endif
617   }
618
619   if (buf) {
620      int num_attribs = 1; /*pos*/
621      num_attribs += exa->num_bound_samplers;
622      if (exa->has_solid_color)
623         ++num_attribs;
624
625      util_draw_vertex_buffer(pipe, buf, 0,
626                              PIPE_PRIM_TRIANGLE_FAN,
627                              4,  /* verts */
628                              num_attribs); /* attribs/vert */
629
630      pipe_buffer_reference(&buf, NULL);
631   }
632}
633
634boolean xorg_solid_bind_state(struct exa_context *exa,
635                              struct exa_pixmap_priv *pixmap,
636                              Pixel fg)
637{
638   unsigned vs_traits, fs_traits;
639   struct xorg_shader shader;
640
641   pixel_to_float4(fg, exa->solid_color);
642   exa->has_solid_color = TRUE;
643
644   exa->solid_color[3] = 1.f;
645
646#if 0
647   debug_printf("Color Pixel=(%d, %d, %d, %d), RGBA=(%f, %f, %f, %f)\n",
648                (fg >> 24) & 0xff, (fg >> 16) & 0xff,
649                (fg >> 8) & 0xff,  (fg >> 0) & 0xff,
650                exa->solid_color[0], exa->solid_color[1],
651                exa->solid_color[2], exa->solid_color[3]);
652#endif
653
654   vs_traits = VS_SOLID_FILL;
655   fs_traits = FS_SOLID_FILL;
656
657   bind_framebuffer_state(exa, pixmap);
658   bind_viewport_state(exa, pixmap);
659   bind_rasterizer_state(exa);
660   bind_blend_state(exa, PictOpSrc, NULL, NULL);
661   setup_constant_buffers(exa, pixmap);
662   bind_clip_state(exa);
663
664   shader = xorg_shaders_get(exa->shaders, vs_traits, fs_traits);
665   cso_set_vertex_shader_handle(exa->cso, shader.vs);
666   cso_set_fragment_shader_handle(exa->cso, shader.fs);
667
668   return TRUE;
669}
670
671void xorg_solid(struct exa_context *exa,
672                struct exa_pixmap_priv *pixmap,
673                int x0, int y0, int x1, int y1)
674{
675   struct pipe_context *pipe = exa->pipe;
676   struct pipe_buffer *buf = 0;
677
678   /* 1st vertex */
679   setup_vertex0(exa->vertices2[0], x0, y0,
680                 exa->solid_color);
681   /* 2nd vertex */
682   setup_vertex0(exa->vertices2[1], x1, y0,
683                 exa->solid_color);
684   /* 3rd vertex */
685   setup_vertex0(exa->vertices2[2], x1, y1,
686                 exa->solid_color);
687   /* 4th vertex */
688   setup_vertex0(exa->vertices2[3], x0, y1,
689                 exa->solid_color);
690
691   buf = pipe_user_buffer_create(exa->pipe->screen,
692                                 exa->vertices2,
693                                 sizeof(exa->vertices2));
694
695
696   if (buf) {
697      util_draw_vertex_buffer(pipe, buf, 0,
698                              PIPE_PRIM_TRIANGLE_FAN,
699                              4,  /* verts */
700                              2); /* attribs/vert */
701
702      pipe_buffer_reference(&buf, NULL);
703   }
704}
705
706
707static INLINE void shift_rectx(float coords[4],
708                               const float *bounds,
709                               const float shift)
710{
711   coords[0] += shift;
712   coords[2] -= shift;
713   if (bounds) {
714      coords[2] = MIN2(coords[2], bounds[2]);
715      /* bound x/y + width/height */
716      if ((coords[0] + coords[2]) > (bounds[0] + bounds[2])) {
717         coords[2] = (bounds[0] + bounds[2]) - coords[0];
718      }
719   }
720}
721
722static INLINE void shift_recty(float coords[4],
723                               const float *bounds,
724                               const float shift)
725{
726   coords[1] += shift;
727   coords[3] -= shift;
728   if (bounds) {
729      coords[3] = MIN2(coords[3], bounds[3]);
730      if ((coords[1] + coords[3]) > (bounds[1] + bounds[3])) {
731         coords[3] = (bounds[1] + bounds[3]) - coords[1];
732      }
733   }
734}
735
736static INLINE void bound_rect(float coords[4],
737                              const float bounds[4],
738                              float shift[4])
739{
740   /* if outside the bounds */
741   if (coords[0] > (bounds[0] + bounds[2]) ||
742       coords[1] > (bounds[1] + bounds[3]) ||
743       (coords[0] + coords[2]) < bounds[0] ||
744       (coords[1] + coords[3]) < bounds[1]) {
745      coords[0] = 0.f;
746      coords[1] = 0.f;
747      coords[2] = 0.f;
748      coords[3] = 0.f;
749      shift[0] = 0.f;
750      shift[1] = 0.f;
751      return;
752   }
753
754   /* bound x */
755   if (coords[0] < bounds[0]) {
756      shift[0] = bounds[0] - coords[0];
757      coords[2] -= shift[0];
758      coords[0] = bounds[0];
759   } else
760      shift[0] = 0.f;
761
762   /* bound y */
763   if (coords[1] < bounds[1]) {
764      shift[1] = bounds[1] - coords[1];
765      coords[3] -= shift[1];
766      coords[1] = bounds[1];
767   } else
768      shift[1] = 0.f;
769
770   shift[2] = bounds[2] - coords[2];
771   shift[3] = bounds[3] - coords[3];
772   /* bound width/height */
773   coords[2] = MIN2(coords[2], bounds[2]);
774   coords[3] = MIN2(coords[3], bounds[3]);
775
776   /* bound x/y + width/height */
777   if ((coords[0] + coords[2]) > (bounds[0] + bounds[2])) {
778      coords[2] = (bounds[0] + bounds[2]) - coords[0];
779   }
780   if ((coords[1] + coords[3]) > (bounds[1] + bounds[3])) {
781      coords[3] = (bounds[1] + bounds[3]) - coords[1];
782   }
783
784   /* if outside the bounds */
785   if ((coords[0] + coords[2]) < bounds[0] ||
786       (coords[1] + coords[3]) < bounds[1]) {
787      coords[0] = 0.f;
788      coords[1] = 0.f;
789      coords[2] = 0.f;
790      coords[3] = 0.f;
791      return;
792   }
793}
794
795static INLINE void sync_size(float *src_loc, float *dst_loc)
796{
797   src_loc[2] = MIN2(src_loc[2], dst_loc[2]);
798   src_loc[3] = MIN2(src_loc[3], dst_loc[3]);
799   dst_loc[2] = src_loc[2];
800   dst_loc[3] = src_loc[3];
801}
802
803
804static void renderer_copy_texture(struct exa_context *exa,
805                                  struct pipe_texture *src,
806                                  float sx1, float sy1,
807                                  float sx2, float sy2,
808                                  struct pipe_texture *dst,
809                                  float dx1, float dy1,
810                                  float dx2, float dy2)
811{
812   struct pipe_context *pipe = exa->pipe;
813   struct pipe_screen *screen = pipe->screen;
814   struct pipe_buffer *buf;
815   struct pipe_surface *dst_surf = screen->get_tex_surface(
816      screen, dst, 0, 0, 0,
817      PIPE_BUFFER_USAGE_GPU_WRITE);
818   struct pipe_framebuffer_state fb;
819   float s0, t0, s1, t1;
820   struct xorg_shader shader;
821
822   assert(src->width[0] != 0);
823   assert(src->height[0] != 0);
824   assert(dst->width[0] != 0);
825   assert(dst->height[0] != 0);
826
827#if 1
828   s0 = sx1 / src->width[0];
829   s1 = sx2 / src->width[0];
830   t0 = sy1 / src->height[0];
831   t1 = sy2 / src->height[0];
832#else
833   s0 = 0;
834   s1 = 1;
835   t0 = 0;
836   t1 = 1;
837#endif
838
839#if 1
840   debug_printf("copy texture src=[%f, %f, %f, %f], dst=[%f, %f, %f, %f], tex=[%f, %f, %f, %f]\n",
841                sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2,
842                s0, t0, s1, t1);
843#endif
844
845   assert(screen->is_format_supported(screen, dst_surf->format,
846                                      PIPE_TEXTURE_2D,
847                                      PIPE_TEXTURE_USAGE_RENDER_TARGET,
848                                      0));
849
850   /* save state (restored below) */
851   cso_save_blend(exa->cso);
852   cso_save_samplers(exa->cso);
853   cso_save_sampler_textures(exa->cso);
854   cso_save_framebuffer(exa->cso);
855   cso_save_fragment_shader(exa->cso);
856   cso_save_vertex_shader(exa->cso);
857
858   cso_save_viewport(exa->cso);
859
860
861   /* set misc state we care about */
862   {
863      struct pipe_blend_state blend;
864      memset(&blend, 0, sizeof(blend));
865      blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE;
866      blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE;
867      blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
868      blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
869      blend.colormask = PIPE_MASK_RGBA;
870      cso_set_blend(exa->cso, &blend);
871   }
872
873   /* sampler */
874   {
875      struct pipe_sampler_state sampler;
876      memset(&sampler, 0, sizeof(sampler));
877      sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
878      sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
879      sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
880      sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
881      sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
882      sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
883      sampler.normalized_coords = 1;
884      cso_single_sampler(exa->cso, 0, &sampler);
885      cso_single_sampler_done(exa->cso);
886   }
887
888   set_viewport(exa, dst_surf->width, dst_surf->height, Y0_TOP);
889
890   /* texture */
891   cso_set_sampler_textures(exa->cso, 1, &src);
892
893   /* shaders */
894   shader = xorg_shaders_get(exa->shaders,
895                             VS_COMPOSITE,
896                             FS_COMPOSITE);
897   cso_set_vertex_shader_handle(exa->cso, shader.vs);
898   cso_set_fragment_shader_handle(exa->cso, shader.fs);
899
900   /* drawing dest */
901   memset(&fb, 0, sizeof(fb));
902   fb.width = dst_surf->width;
903   fb.height = dst_surf->height;
904   fb.nr_cbufs = 1;
905   fb.cbufs[0] = dst_surf;
906   {
907      int i;
908      for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i)
909         fb.cbufs[i] = 0;
910   }
911   cso_set_framebuffer(exa->cso, &fb);
912   setup_vs_constant_buffer(exa, fb.width, fb.height);
913   setup_fs_constant_buffer(exa);
914
915   /* draw quad */
916   buf = setup_vertex_data_tex(exa,
917                               dx1, dy1,
918                               dx2, dy2,
919                               s0, t0, s1, t1,
920                               0.0f);
921
922   if (buf) {
923      util_draw_vertex_buffer(exa->pipe, buf, 0,
924                              PIPE_PRIM_TRIANGLE_FAN,
925                              4,  /* verts */
926                              2); /* attribs/vert */
927
928      pipe_buffer_reference(&buf, NULL);
929   }
930
931   /* restore state we changed */
932   cso_restore_blend(exa->cso);
933   cso_restore_samplers(exa->cso);
934   cso_restore_sampler_textures(exa->cso);
935   cso_restore_framebuffer(exa->cso);
936   cso_restore_vertex_shader(exa->cso);
937   cso_restore_fragment_shader(exa->cso);
938   cso_restore_viewport(exa->cso);
939
940   pipe_surface_reference(&dst_surf, NULL);
941}
942
943
944static struct pipe_texture *
945create_sampler_texture(struct exa_context *ctx,
946                       struct pipe_texture *src)
947{
948   enum pipe_format format;
949   struct pipe_context *pipe = ctx->pipe;
950   struct pipe_screen *screen = pipe->screen;
951   struct pipe_texture *pt;
952   struct pipe_texture templ;
953
954   pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
955
956   /* the coming in texture should already have that invariance */
957   debug_assert(screen->is_format_supported(screen, src->format,
958                                            PIPE_TEXTURE_2D,
959                                            PIPE_TEXTURE_USAGE_SAMPLER, 0));
960
961   format = src->format;
962
963   memset(&templ, 0, sizeof(templ));
964   templ.target = PIPE_TEXTURE_2D;
965   templ.format = format;
966   templ.last_level = 0;
967   templ.width[0] = src->width[0];
968   templ.height[0] = src->height[0];
969   templ.depth[0] = 1;
970   pf_get_block(format, &templ.block);
971   templ.tex_usage = PIPE_TEXTURE_USAGE_SAMPLER;
972
973   pt = screen->texture_create(screen, &templ);
974
975   debug_assert(!pt || pipe_is_referenced(&pt->reference));
976
977   if (!pt)
978      return NULL;
979
980   {
981      /* copy source framebuffer surface into texture */
982      struct pipe_surface *ps_read = screen->get_tex_surface(
983         screen, src, 0, 0, 0, PIPE_BUFFER_USAGE_GPU_READ);
984      struct pipe_surface *ps_tex = screen->get_tex_surface(
985         screen, pt, 0, 0, 0, PIPE_BUFFER_USAGE_GPU_WRITE );
986      pipe->surface_copy(pipe,
987			 ps_tex, /* dest */
988			 0, 0, /* destx/y */
989			 ps_read,
990			 0, 0, src->width[0], src->height[0]);
991      pipe_surface_reference(&ps_read, NULL);
992      pipe_surface_reference(&ps_tex, NULL);
993   }
994
995   return pt;
996}
997
998void xorg_copy_pixmap(struct exa_context *ctx,
999                      struct exa_pixmap_priv *dst_priv, int dx, int dy,
1000                      struct exa_pixmap_priv *src_priv, int sx, int sy,
1001                      int width, int height)
1002{
1003   float dst_loc[4], src_loc[4];
1004   float dst_bounds[4], src_bounds[4];
1005   float src_shift[4], dst_shift[4], shift[4];
1006   struct pipe_texture *dst = dst_priv->tex;
1007   struct pipe_texture *src = src_priv->tex;
1008
1009   xorg_exa_finish(ctx);
1010
1011   dst_loc[0] = dx;
1012   dst_loc[1] = dy;
1013   dst_loc[2] = width;
1014   dst_loc[3] = height;
1015   dst_bounds[0] = 0.f;
1016   dst_bounds[1] = 0.f;
1017   dst_bounds[2] = dst->width[0];
1018   dst_bounds[3] = dst->height[0];
1019
1020   src_loc[0] = sx;
1021   src_loc[1] = sy;
1022   src_loc[2] = width;
1023   src_loc[3] = height;
1024   src_bounds[0] = 0.f;
1025   src_bounds[1] = 0.f;
1026   src_bounds[2] = src->width[0];
1027   src_bounds[3] = src->height[0];
1028
1029   bound_rect(src_loc, src_bounds, src_shift);
1030   bound_rect(dst_loc, dst_bounds, dst_shift);
1031   shift[0] = src_shift[0] - dst_shift[0];
1032   shift[1] = src_shift[1] - dst_shift[1];
1033
1034   if (shift[0] < 0)
1035      shift_rectx(src_loc, src_bounds, -shift[0]);
1036   else
1037      shift_rectx(dst_loc, dst_bounds, shift[0]);
1038
1039   if (shift[1] < 0)
1040      shift_recty(src_loc, src_bounds, -shift[1]);
1041   else
1042      shift_recty(dst_loc, dst_bounds, shift[1]);
1043
1044   sync_size(src_loc, dst_loc);
1045
1046   if (src_loc[2] >= 0 && src_loc[3] >= 0 &&
1047       dst_loc[2] >= 0 && dst_loc[3] >= 0) {
1048      struct pipe_texture *temp_src = src;
1049
1050      if (src == dst)
1051         temp_src = create_sampler_texture(ctx, src);
1052
1053      renderer_copy_texture(ctx,
1054                            temp_src,
1055                            src_loc[0],
1056                            src_loc[1],
1057                            src_loc[0] + src_loc[2],
1058                            src_loc[1] + src_loc[3],
1059                            dst,
1060                            dst_loc[0],
1061                            dst_loc[1],
1062                            dst_loc[0] + dst_loc[2],
1063                            dst_loc[1] + dst_loc[3]);
1064
1065      if (src == dst)
1066         pipe_texture_reference(&temp_src, NULL);
1067   }
1068}
1069
1070