Merge branch 'master' into pipe-format-simplify
[mesa.git] / src / gallium / state_trackers / xorg / xorg_composite.c
index f8a3d7ba8aaf8f98f647be5f7c02af9673164f18..1c248a629e681e24625a98125bb6d0323492d761 100644 (file)
@@ -1,5 +1,6 @@
 #include "xorg_composite.h"
 
+#include "xorg_renderer.h"
 #include "xorg_exa_tgsi.h"
 
 #include "cso_cache/cso_context.h"
@@ -8,37 +9,47 @@
 
 #include "pipe/p_inlines.h"
 
+/*XXX also in Xrender.h but the including it here breaks compilition */
+#define XFixedToDouble(f)    (((double) (f)) / 65536.)
+
 struct xorg_composite_blend {
-   int op:8;
+   int op : 8;
 
-   unsigned rgb_src_factor:5;    /**< PIPE_BLENDFACTOR_x */
-   unsigned alpha_src_factor:5;  /**< PIPE_BLENDFACTOR_x */
+   unsigned alpha_dst : 4;
+   unsigned alpha_src : 4;
 
-   unsigned rgb_dst_factor:5;    /**< PIPE_BLENDFACTOR_x */
-   unsigned alpha_dst_factor:5;  /**< PIPE_BLENDFACTOR_x */
+   unsigned rgb_src : 8;    /**< PIPE_BLENDFACTOR_x */
+   unsigned rgb_dst : 8;    /**< PIPE_BLENDFACTOR_x */
 };
 
 #define BLEND_OP_OVER 3
 static const struct xorg_composite_blend xorg_blends[] = {
    { PictOpClear,
-     PIPE_BLENDFACTOR_CONST_COLOR, PIPE_BLENDFACTOR_CONST_ALPHA,
-     PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO },
-
+     0, 0, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO},
    { PictOpSrc,
-     PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ONE,
-     PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO },
-
+     0, 0, PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ZERO},
    { PictOpDst,
-     PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO,
-     PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ONE },
-
+     0, 0, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ONE},
    { PictOpOver,
-     PIPE_BLENDFACTOR_SRC_ALPHA, PIPE_BLENDFACTOR_ONE,
-     PIPE_BLENDFACTOR_INV_SRC_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA },
-
+     0, 1, PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_INV_SRC_ALPHA},
    { PictOpOverReverse,
-     PIPE_BLENDFACTOR_SRC_ALPHA, PIPE_BLENDFACTOR_ONE,
-     PIPE_BLENDFACTOR_INV_SRC_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA },
+     1, 0, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_ONE},
+   { PictOpIn,
+     1, 0, PIPE_BLENDFACTOR_DST_ALPHA, PIPE_BLENDFACTOR_ZERO},
+   { PictOpInReverse,
+     0, 1, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_SRC_ALPHA},
+   { PictOpOut,
+     1, 0, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_ZERO},
+   { PictOpOutReverse,
+     0, 1, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_INV_SRC_ALPHA},
+   { PictOpAtop,
+     1, 1, PIPE_BLENDFACTOR_DST_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA},
+   { PictOpAtopReverse,
+     1, 1, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_SRC_ALPHA},
+   { PictOpXor,
+     1, 1, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA},
+   { PictOpAdd,
+     0, 0, PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ONE},
 };
 
 
@@ -57,58 +68,49 @@ pixel_to_float4(Pixel pixel, float *color)
    color[3] = ((float)a) / 255.;
 }
 
-static INLINE void
-render_pixel_to_float4(PictFormatPtr format,
-                       CARD32 pixel, float *color)
-{
-   CARD32          r, g, b, a;
-
-   debug_assert(format->type == PictTypeDirect);
-
-   r = (pixel >> format->direct.red) & format->direct.redMask;
-   g = (pixel >> format->direct.green) & format->direct.greenMask;
-   b = (pixel >> format->direct.blue) & format->direct.blueMask;
-   a = (pixel >> format->direct.alpha) & format->direct.alphaMask;
-   color[0] = ((float)r) / ((float)format->direct.redMask);
-   color[1] = ((float)g) / ((float)format->direct.greenMask);
-   color[2] = ((float)b) / ((float)format->direct.blueMask);
-   color[3] = ((float)a) / ((float)format->direct.alphaMask);
-}
-
-struct acceleration_info {
-   int op : 16;
-   int with_mask : 1;
-   int component_alpha : 1;
-};
-static const struct acceleration_info accelerated_ops[] = {
-   {PictOpClear,       1, 0},
-   {PictOpSrc,         1, 0},
-   {PictOpDst,         1, 0},
-   {PictOpOver,        1, 0},
-   {PictOpOverReverse, 1, 0},
-   {PictOpIn,          1, 0},
-   {PictOpInReverse,   1, 0},
-   {PictOpOut,         1, 0},
-   {PictOpOutReverse,  1, 0},
-   {PictOpAtop,        1, 0},
-   {PictOpAtopReverse, 1, 0},
-   {PictOpXor,         1, 0},
-   {PictOpAdd,         1, 0},
-   {PictOpSaturate,    1, 0},
-};
-
-static struct xorg_composite_blend
-blend_for_op(int op)
+static boolean
+blend_for_op(struct xorg_composite_blend *blend,
+             int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
+             PicturePtr pDstPicture)
 {
    const int num_blends =
       sizeof(xorg_blends)/sizeof(struct xorg_composite_blend);
    int i;
+   boolean supported = FALSE;
+
+   /* our default in case something goes wrong */
+   *blend = xorg_blends[BLEND_OP_OVER];
 
    for (i = 0; i < num_blends; ++i) {
-      if (xorg_blends[i].op == op)
-         return xorg_blends[i];
+      if (xorg_blends[i].op == op) {
+         *blend = xorg_blends[i];
+         supported = TRUE;
+      }
+   }
+
+   /* If there's no dst alpha channel, adjust the blend op so that we'll treat
+    * it as always 1. */
+   if (pDstPicture &&
+       PICT_FORMAT_A(pDstPicture->format) == 0 && blend->alpha_dst) {
+      if (blend->rgb_src == PIPE_BLENDFACTOR_DST_ALPHA)
+         blend->rgb_src = PIPE_BLENDFACTOR_ONE;
+      else if (blend->rgb_src == PIPE_BLENDFACTOR_INV_DST_ALPHA)
+         blend->rgb_src = PIPE_BLENDFACTOR_ZERO;
+   }
+
+   /* If the source alpha is being used, then we should only be in a case where
+    * the source blend factor is 0, and the source blend value is the mask
+    * channels multiplied by the source picture's alpha. */
+   if (pMaskPicture && pMaskPicture->componentAlpha &&
+       PICT_FORMAT_RGB(pMaskPicture->format) && blend->alpha_src) {
+      if (blend->rgb_dst == PIPE_BLENDFACTOR_SRC_ALPHA) {
+         blend->rgb_dst = PIPE_BLENDFACTOR_SRC_COLOR;
+      } else if (blend->rgb_dst == PIPE_BLENDFACTOR_INV_SRC_ALPHA) {
+         blend->rgb_dst = PIPE_BLENDFACTOR_INV_SRC_COLOR;
+      }
    }
-   return xorg_blends[BLEND_OP_OVER];
+
+   return supported;
 }
 
 static INLINE int
@@ -116,7 +118,7 @@ render_repeat_to_gallium(int mode)
 {
    switch(mode) {
    case RepeatNone:
-      return PIPE_TEX_WRAP_CLAMP;
+      return PIPE_TEX_WRAP_CLAMP_TO_BORDER;
    case RepeatNormal:
       return PIPE_TEX_WRAP_REPEAT;
    case RepeatReflect:
@@ -129,171 +131,44 @@ render_repeat_to_gallium(int mode)
    return PIPE_TEX_WRAP_REPEAT;
 }
 
+static INLINE boolean
+render_filter_to_gallium(int xrender_filter, int *out_filter)
+{
+
+   switch (xrender_filter) {
+   case PictFilterNearest:
+      *out_filter = PIPE_TEX_FILTER_NEAREST;
+      break;
+   case PictFilterBilinear:
+      *out_filter = PIPE_TEX_FILTER_LINEAR;
+      break;
+   case PictFilterFast:
+      *out_filter = PIPE_TEX_FILTER_NEAREST;
+      break;
+   case PictFilterGood:
+      *out_filter = PIPE_TEX_FILTER_LINEAR;
+      break;
+   case PictFilterBest:
+      *out_filter = PIPE_TEX_FILTER_LINEAR;
+      break;
+   case PictFilterConvolution:
+      *out_filter = PIPE_TEX_FILTER_NEAREST;
+      return FALSE;
+   default:
+      debug_printf("Unknown xrender filter\n");
+      *out_filter = PIPE_TEX_FILTER_NEAREST;
+      return FALSE;
+   }
 
-static INLINE void
-setup_vertex0(float vertex[2][4], float x, float y,
-              float color[4])
-{
-   vertex[0][0] = x;
-   vertex[0][1] = y;
-   vertex[0][2] = 0.f; /*z*/
-   vertex[0][3] = 1.f; /*w*/
-
-   vertex[1][0] = color[0]; /*r*/
-   vertex[1][1] = color[1]; /*g*/
-   vertex[1][2] = color[2]; /*b*/
-   vertex[1][3] = color[3]; /*a*/
-}
-
-static struct pipe_buffer *
-setup_vertex_data0(struct exa_context *ctx,
-                   int srcX, int srcY, int maskX, int maskY,
-                   int dstX, int dstY, int width, int height)
-{
-   /* 1st vertex */
-   setup_vertex0(ctx->vertices2[0], dstX, dstY,
-                 ctx->solid_color);
-   /* 2nd vertex */
-   setup_vertex0(ctx->vertices2[1], dstX + width, dstY,
-                 ctx->solid_color);
-   /* 3rd vertex */
-   setup_vertex0(ctx->vertices2[2], dstX + width, dstY + height,
-                 ctx->solid_color);
-   /* 4th vertex */
-   setup_vertex0(ctx->vertices2[3], dstX, dstY + height,
-                 ctx->solid_color);
-
-   return pipe_user_buffer_create(ctx->pipe->screen,
-                                  ctx->vertices2,
-                                  sizeof(ctx->vertices2));
-}
-
-static INLINE void
-setup_vertex1(float vertex[2][4], float x, float y, float s, float t)
-{
-   vertex[0][0] = x;
-   vertex[0][1] = y;
-   vertex[0][2] = 0.f; /*z*/
-   vertex[0][3] = 1.f; /*w*/
-
-   vertex[1][0] = s;   /*s*/
-   vertex[1][1] = t;   /*t*/
-   vertex[1][2] = 0.f; /*r*/
-   vertex[1][3] = 1.f; /*q*/
-}
-
-static struct pipe_buffer *
-setup_vertex_data1(struct exa_context *ctx,
-                   int srcX, int srcY, int maskX, int maskY,
-                   int dstX, int dstY, int width, int height)
-{
-   float s0, t0, s1, t1;
-   struct pipe_texture *src = ctx->bound_textures[0];
-
-   s0 = srcX / src->width[0];
-   s1 = srcX + width / src->width[0];
-   t0 = srcY / src->height[0];
-   t1 = srcY + height / src->height[0];
-
-   /* 1st vertex */
-   setup_vertex1(ctx->vertices2[0], dstX, dstY,
-                 s0, t0);
-   /* 2nd vertex */
-   setup_vertex1(ctx->vertices2[1], dstX + width, dstY,
-                 s1, t0);
-   /* 3rd vertex */
-   setup_vertex1(ctx->vertices2[2], dstX + width, dstY + height,
-                 s1, t1);
-   /* 4th vertex */
-   setup_vertex1(ctx->vertices2[3], dstX, dstY + height,
-                 s0, t1);
-
-   return pipe_user_buffer_create(ctx->pipe->screen,
-                                  ctx->vertices2,
-                                  sizeof(ctx->vertices2));
-}
-
-static struct pipe_buffer *
-setup_vertex_data_tex(struct exa_context *ctx,
-                      float x0, float y0, float x1, float y1,
-                      float s0, float t0, float s1, float t1,
-                      float z)
-{
-   /* 1st vertex */
-   setup_vertex1(ctx->vertices2[0], x0, y0,
-                 s0, t0);
-   /* 2nd vertex */
-   setup_vertex1(ctx->vertices2[1], x1, y0,
-                 s1, t0);
-   /* 3rd vertex */
-   setup_vertex1(ctx->vertices2[2], x1, y1,
-                 s1, t1);
-   /* 4th vertex */
-   setup_vertex1(ctx->vertices2[3], x0, y1,
-                 s0, t1);
-
-   return pipe_user_buffer_create(ctx->pipe->screen,
-                                  ctx->vertices2,
-                                  sizeof(ctx->vertices2));
-}
-
-
-
-static INLINE void
-setup_vertex2(float vertex[3][4], float x, float y,
-              float s0, float t0, float s1, float t1)
-{
-   vertex[0][0] = x;
-   vertex[0][1] = y;
-   vertex[0][2] = 0.f; /*z*/
-   vertex[0][3] = 1.f; /*w*/
-
-   vertex[1][0] = s0;  /*s*/
-   vertex[1][1] = t0;  /*t*/
-   vertex[1][2] = 0.f; /*r*/
-   vertex[1][3] = 1.f; /*q*/
-
-   vertex[2][0] = s1;  /*s*/
-   vertex[2][1] = t1;  /*t*/
-   vertex[2][2] = 0.f; /*r*/
-   vertex[2][3] = 1.f; /*q*/
+   return TRUE;
 }
 
-static struct pipe_buffer *
-setup_vertex_data2(struct exa_context *ctx,
-                   int srcX, int srcY, int maskX, int maskY,
-                   int dstX, int dstY, int width, int height)
+static boolean is_filter_accelerated(PicturePtr pic)
 {
-   float st0[4], st1[4];
-   struct pipe_texture *src = ctx->bound_textures[0];
-   struct pipe_texture *mask = ctx->bound_textures[0];
-
-   st0[0] = srcX / src->width[0];
-   st0[1] = srcY / src->height[0];
-   st0[2] = srcX + width / src->width[0];
-   st0[3] = srcY + height / src->height[0];
-
-   st1[0] = maskX / mask->width[0];
-   st1[1] = maskY / mask->height[0];
-   st1[2] = maskX + width / mask->width[0];
-   st1[3] = maskY + height / mask->height[0];
-
-   /* 1st vertex */
-   setup_vertex2(ctx->vertices3[0], dstX, dstY,
-                 st0[0], st0[1], st1[0], st1[1]);
-   /* 2nd vertex */
-   setup_vertex2(ctx->vertices3[1], dstX + width, dstY,
-                 st0[2], st0[1], st1[2], st1[1]);
-   /* 3rd vertex */
-   setup_vertex2(ctx->vertices3[2], dstX + width, dstY + height,
-                 st0[2], st0[3], st1[2], st1[3]);
-   /* 4th vertex */
-   setup_vertex2(ctx->vertices3[3], dstX, dstY + height,
-                 st0[0], st0[3], st1[0], st1[3]);
-
-   return pipe_user_buffer_create(ctx->pipe->screen,
-                                  ctx->vertices3,
-                                  sizeof(ctx->vertices3));
+   int filter;
+   if (pic && !render_filter_to_gallium(pic->filter, &filter))
+       return FALSE;
+   return TRUE;
 }
 
 boolean xorg_composite_accelerated(int op,
@@ -301,132 +176,127 @@ boolean xorg_composite_accelerated(int op,
                                    PicturePtr pMaskPicture,
                                    PicturePtr pDstPicture)
 {
-   unsigned i;
-   unsigned accel_ops_count =
-      sizeof(accelerated_ops)/sizeof(struct acceleration_info);
+   ScreenPtr pScreen = pDstPicture->pDrawable->pScreen;
+   ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+   modesettingPtr ms = modesettingPTR(pScrn);
+   struct xorg_composite_blend blend;
 
-   if (pSrcPicture) {
-      /* component alpha not supported */
-      if (pSrcPicture->componentAlpha)
-         return FALSE;
+   if (!is_filter_accelerated(pSrcPicture) ||
+       !is_filter_accelerated(pMaskPicture)) {
+      XORG_FALLBACK("Unsupported Xrender filter");
    }
 
-   for (i = 0; i < accel_ops_count; ++i) {
-      if (op == accelerated_ops[i].op) {
-         if (pMaskPicture && !accelerated_ops[i].with_mask)
-            return FALSE;
-         return TRUE;
-      }
+   if (pSrcPicture->pSourcePict) {
+      if (pSrcPicture->pSourcePict->type != SourcePictTypeSolidFill)
+         XORG_FALLBACK("Gradients not enabled (haven't been well tested)");
    }
-   return FALSE;
-}
-
-static void
-bind_clip_state(struct exa_context *exa)
-{
-}
-
-static void
-bind_framebuffer_state(struct exa_context *exa, struct exa_pixmap_priv *pDst)
-{
-   unsigned i;
-   struct pipe_framebuffer_state state;
-   struct pipe_surface *surface = exa_gpu_surface(exa, pDst);
-   memset(&state, 0, sizeof(struct pipe_framebuffer_state));
-
-   state.width  = pDst->tex->width[0];
-   state.height = pDst->tex->height[0];
-
-   state.nr_cbufs = 1;
-   state.cbufs[0] = surface;
-   for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i)
-      state.cbufs[i] = 0;
-
-   /* currently we don't use depth/stencil */
-   state.zsbuf = 0;
-
-   cso_set_framebuffer(exa->cso, &state);
-
-   /* we do fire and forget for the framebuffer, this is the forget part */
-   pipe_surface_reference(&surface, NULL);
-}
-
-enum AxisOrientation {
-   Y0_BOTTOM,
-   Y0_TOP
-};
-
-static void
-set_viewport(struct exa_context *exa, int width, int height,
-             enum AxisOrientation orientation)
-{
-   struct pipe_viewport_state viewport;
-   float y_scale = (orientation == Y0_BOTTOM) ? -2.f : 2.f;
-
-   viewport.scale[0] =  width / 2.f;
-   viewport.scale[1] =  height / y_scale;
-   viewport.scale[2] =  1.0;
-   viewport.scale[3] =  1.0;
-   viewport.translate[0] = width / 2.f;
-   viewport.translate[1] = height / 2.f;
-   viewport.translate[2] = 0.0;
-   viewport.translate[3] = 0.0;
-
-   cso_set_viewport(exa->cso, &viewport);
-}
 
-static void
-bind_viewport_state(struct exa_context *exa, struct exa_pixmap_priv *pDst)
-{
-   int width = pDst->tex->width[0];
-   int height = pDst->tex->height[0];
-
-   /*debug_printf("Bind viewport (%d, %d)\n", width, height);*/
+   if (blend_for_op(&blend, op,
+                    pSrcPicture, pMaskPicture, pDstPicture)) {
+      /* Check for component alpha */
+      if (pMaskPicture && pMaskPicture->componentAlpha &&
+          PICT_FORMAT_RGB(pMaskPicture->format)) {
+         if (blend.alpha_src && blend.rgb_src != PIPE_BLENDFACTOR_ZERO) {
+            XORG_FALLBACK("Component alpha not supported with source "
+                          "alpha and source value blending. (op=%d)",
+                          op);
+         }
+      }
 
-   set_viewport(exa, width, height, Y0_TOP);
+      return TRUE;
+   }
+   XORG_FALLBACK("Unsupported composition operation = %d", op);
 }
 
 static void
 bind_blend_state(struct exa_context *exa, int op,
-                 PicturePtr pSrcPicture, PicturePtr pMaskPicture)
+                 PicturePtr pSrcPicture,
+                 PicturePtr pMaskPicture,
+                 PicturePtr pDstPicture)
 {
-   boolean component_alpha = (pSrcPicture) ?
-                             pSrcPicture->componentAlpha : FALSE;
    struct xorg_composite_blend blend_opt;
    struct pipe_blend_state blend;
 
-   if (component_alpha) {
-      op = PictOpOver;
-   }
-   blend_opt = blend_for_op(op);
+   blend_for_op(&blend_opt, op, pSrcPicture, pMaskPicture, pDstPicture);
 
    memset(&blend, 0, sizeof(struct pipe_blend_state));
    blend.blend_enable = 1;
-   blend.colormask |= PIPE_MASK_R;
-   blend.colormask |= PIPE_MASK_G;
-   blend.colormask |= PIPE_MASK_B;
-   blend.colormask |= PIPE_MASK_A;
+   blend.colormask |= PIPE_MASK_RGBA;
+
+   blend.rgb_src_factor   = blend_opt.rgb_src;
+   blend.alpha_src_factor = blend_opt.rgb_src;
+   blend.rgb_dst_factor   = blend_opt.rgb_dst;
+   blend.alpha_dst_factor = blend_opt.rgb_dst;
+
+   cso_set_blend(exa->renderer->cso, &blend);
+}
+
+static unsigned
+picture_format_fixups(struct exa_pixmap_priv *pSrc, PicturePtr pSrcPicture, boolean mask,
+                      PicturePtr pDstPicture)
+{
+   boolean set_alpha = FALSE;
+   boolean swizzle = FALSE;
+   unsigned ret = 0;
+
+   if (pSrc->picture_format == pSrcPicture->format) {
+      if (pSrc->picture_format == PICT_a8) {
+         if (mask)
+            return FS_MASK_LUMINANCE;
+         else if (pDstPicture->format != PICT_a8) {
+            /* if both dst and src are luminance then
+             * we don't want to swizzle the alpha (X) of the
+             * source into W component of the dst because
+             * it will break our destination */
+            return FS_SRC_LUMINANCE;
+         }
+      }
+      return 0;
+   }
 
-   blend.rgb_src_factor   = blend_opt.rgb_src_factor;
-   blend.alpha_src_factor = blend_opt.alpha_src_factor;
-   blend.rgb_dst_factor   = blend_opt.rgb_dst_factor;
-   blend.alpha_dst_factor = blend_opt.alpha_dst_factor;
+   if (pSrc->picture_format != PICT_a8r8g8b8) {
+      assert(!"can not handle formats");
+      return 0;
+   }
 
-   cso_set_blend(exa->cso, &blend);
-}
+   /* pSrc->picture_format == PICT_a8r8g8b8 */
+   switch (pSrcPicture->format) {
+   case PICT_x8b8g8r8:
+   case PICT_b8g8r8:
+      set_alpha = TRUE; /* fall trough */
+   case PICT_a8b8g8r8:
+      swizzle = TRUE;
+      break;
+   case PICT_x8r8g8b8:
+   case PICT_r8g8b8:
+      set_alpha = TRUE; /* fall through */
+   case PICT_a8r8g8b8:
+      break;
+#ifdef PICT_TYPE_BGRA
+   case PICT_b8g8r8a8:
+   case PICT_b8g8r8x8:
+   case PICT_a2r10g10b10:
+   case PICT_x2r10g10b10:
+   case PICT_a2b10g10r10:
+   case PICT_x2b10g10r10:
+#endif
+   default:
+      assert(!"can not handle formats");
+      return 0;
+   }
 
-static void
-bind_rasterizer_state(struct exa_context *exa)
-{
-   struct pipe_rasterizer_state raster;
-   memset(&raster, 0, sizeof(struct pipe_rasterizer_state));
-   raster.gl_rasterization_rules = 1;
-   cso_set_rasterizer(exa->cso, &raster);
+   if (set_alpha)
+      ret |= mask ? FS_MASK_SET_ALPHA : FS_SRC_SET_ALPHA;
+   if (swizzle)
+      ret |= mask ? FS_MASK_SWIZZLE_RGB : FS_SRC_SWIZZLE_RGB;
+
+   return ret;
 }
 
 static void
 bind_shaders(struct exa_context *exa, int op,
-             PicturePtr pSrcPicture, PicturePtr pMaskPicture)
+             PicturePtr pSrcPicture, PicturePtr pMaskPicture, PicturePtr pDstPicture,
+             struct exa_pixmap_priv *pSrc, struct exa_pixmap_priv *pMask)
 {
    unsigned vs_traits = 0, fs_traits = 0;
    struct xorg_shader shader;
@@ -434,13 +304,16 @@ bind_shaders(struct exa_context *exa, int op,
    exa->has_solid_color = FALSE;
 
    if (pSrcPicture) {
+      if (pSrcPicture->repeatType == RepeatNone && pSrcPicture->transform)
+         fs_traits |= FS_SRC_REPEAT_NONE;
+
       if (pSrcPicture->pSourcePict) {
          if (pSrcPicture->pSourcePict->type == SourcePictTypeSolidFill) {
             fs_traits |= FS_SOLID_FILL;
             vs_traits |= VS_SOLID_FILL;
-            render_pixel_to_float4(pSrcPicture->pFormat,
-                                   pSrcPicture->pSourcePict->solidFill.color,
-                                   exa->solid_color);
+            debug_assert(pSrcPicture->format == PICT_a8r8g8b8);
+            pixel_to_float4(pSrcPicture->pSourcePict->solidFill.color,
+                            exa->solid_color);
             exa->has_solid_color = TRUE;
          } else {
             debug_assert("!gradients not supported");
@@ -449,19 +322,33 @@ bind_shaders(struct exa_context *exa, int op,
          fs_traits |= FS_COMPOSITE;
          vs_traits |= VS_COMPOSITE;
       }
+
+      fs_traits |= picture_format_fixups(pSrc, pSrcPicture, FALSE, pDstPicture);
    }
 
    if (pMaskPicture) {
       vs_traits |= VS_MASK;
       fs_traits |= FS_MASK;
+      if (pMaskPicture->repeatType == RepeatNone && pMaskPicture->transform)
+         fs_traits |= FS_MASK_REPEAT_NONE;
+      if (pMaskPicture->componentAlpha) {
+         struct xorg_composite_blend blend;
+         blend_for_op(&blend, op,
+                      pSrcPicture, pMaskPicture, NULL);
+         if (blend.alpha_src) {
+            fs_traits |= FS_CA_SRCALPHA;
+         } else
+            fs_traits |= FS_CA_FULL;
+      }
+
+      fs_traits |= picture_format_fixups(pMask, pMaskPicture, TRUE, pDstPicture);
    }
 
-   shader = xorg_shaders_get(exa->shaders, vs_traits, fs_traits);
-   cso_set_vertex_shader_handle(exa->cso, shader.vs);
-   cso_set_fragment_shader_handle(exa->cso, shader.fs);
+   shader = xorg_shaders_get(exa->renderer->shaders, vs_traits, fs_traits);
+   cso_set_vertex_shader_handle(exa->renderer->cso, shader.vs);
+   cso_set_fragment_shader_handle(exa->renderer->cso, shader.fs);
 }
 
-
 static void
 bind_samplers(struct exa_context *exa, int op,
               PicturePtr pSrcPicture, PicturePtr pMaskPicture,
@@ -475,94 +362,103 @@ bind_samplers(struct exa_context *exa, int op,
 
    exa->num_bound_samplers = 0;
 
+#if 0
+   if ((pSrc && (exa->pipe->is_texture_referenced(exa->pipe, pSrc->tex, 0, 0) &
+                 PIPE_REFERENCED_FOR_WRITE)) ||
+       (pMask && (exa->pipe->is_texture_referenced(exa->pipe, pMask->tex, 0, 0) &
+        PIPE_REFERENCED_FOR_WRITE)))
+      xorg_exa_flush(exa, PIPE_FLUSH_RENDER_CACHE, NULL);
+#endif
+
    memset(&src_sampler, 0, sizeof(struct pipe_sampler_state));
    memset(&mask_sampler, 0, sizeof(struct pipe_sampler_state));
 
    if (pSrcPicture && pSrc) {
-      unsigned src_wrap = render_repeat_to_gallium(
-         pSrcPicture->repeatType);
-      src_sampler.wrap_s = src_wrap;
-      src_sampler.wrap_t = src_wrap;
-      src_sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
-      src_sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
-      src_sampler.normalized_coords = 1;
-      samplers[0] = &src_sampler;
-      exa->bound_textures[0] = pSrc->tex;
-      ++exa->num_bound_samplers;
+      if (exa->has_solid_color) {
+         debug_assert(!"solid color with textures");
+         samplers[0] = NULL;
+         exa->bound_textures[0] = NULL;
+      } else {
+         unsigned src_wrap = render_repeat_to_gallium(
+            pSrcPicture->repeatType);
+         int filter;
+
+         render_filter_to_gallium(pSrcPicture->filter, &filter);
+
+         src_sampler.wrap_s = src_wrap;
+         src_sampler.wrap_t = src_wrap;
+         src_sampler.min_img_filter = filter;
+         src_sampler.mag_img_filter = filter;
+         src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST;
+         src_sampler.normalized_coords = 1;
+         samplers[0] = &src_sampler;
+         exa->bound_textures[0] = pSrc->tex;
+         exa->num_bound_samplers = 1;
+      }
    }
 
    if (pMaskPicture && pMask) {
       unsigned mask_wrap = render_repeat_to_gallium(
          pMaskPicture->repeatType);
+      int filter;
+
+      render_filter_to_gallium(pMaskPicture->filter, &filter);
+
       mask_sampler.wrap_s = mask_wrap;
       mask_sampler.wrap_t = mask_wrap;
-      mask_sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
-      mask_sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
+      mask_sampler.min_img_filter = filter;
+      mask_sampler.mag_img_filter = filter;
+      src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST;
       mask_sampler.normalized_coords = 1;
       samplers[1] = &mask_sampler;
       exa->bound_textures[1] = pMask->tex;
-      ++exa->num_bound_samplers;
+      exa->num_bound_samplers = 2;
    }
 
-   cso_set_samplers(exa->cso, exa->num_bound_samplers,
+   cso_set_samplers(exa->renderer->cso, exa->num_bound_samplers,
                     (const struct pipe_sampler_state **)samplers);
-   cso_set_sampler_textures(exa->cso, exa->num_bound_samplers,
+   cso_set_sampler_textures(exa->renderer->cso, exa->num_bound_samplers,
                             exa->bound_textures);
 }
 
-static void
-setup_vs_constant_buffer(struct exa_context *exa,
-                         int width, int height)
-{
-   const int param_bytes = 8 * sizeof(float);
-   float vs_consts[8] = {
-      2.f/width, 2.f/height, 1, 1,
-      -1, -1, 0, 0
-   };
-   struct pipe_constant_buffer *cbuf = &exa->vs_const_buffer;
-
-   pipe_buffer_reference(&cbuf->buffer, NULL);
-   cbuf->buffer = pipe_buffer_create(exa->pipe->screen, 16,
-                                     PIPE_BUFFER_USAGE_CONSTANT,
-                                     param_bytes);
-
-   if (cbuf->buffer) {
-      pipe_buffer_write(exa->pipe->screen, cbuf->buffer,
-                        0, param_bytes, vs_consts);
-   }
-   exa->pipe->set_constant_buffer(exa->pipe, PIPE_SHADER_VERTEX, 0, cbuf);
-}
 
 
-static void
-setup_fs_constant_buffer(struct exa_context *exa)
+static INLINE boolean matrix_from_pict_transform(PictTransform *trans, float *matrix)
 {
-   const int param_bytes = 4 * sizeof(float);
-   float fs_consts[8] = {
-      0, 0, 0, 1,
-   };
-   struct pipe_constant_buffer *cbuf = &exa->fs_const_buffer;
-
-   pipe_buffer_reference(&cbuf->buffer, NULL);
-   cbuf->buffer = pipe_buffer_create(exa->pipe->screen, 16,
-                                     PIPE_BUFFER_USAGE_CONSTANT,
-                                     param_bytes);
-
-   if (cbuf->buffer) {
-      pipe_buffer_write(exa->pipe->screen, cbuf->buffer,
-                        0, param_bytes, fs_consts);
-   }
-   exa->pipe->set_constant_buffer(exa->pipe, PIPE_SHADER_FRAGMENT, 0, cbuf);
+   if (!trans)
+      return FALSE;
+
+   matrix[0] = XFixedToDouble(trans->matrix[0][0]);
+   matrix[3] = XFixedToDouble(trans->matrix[0][1]);
+   matrix[6] = XFixedToDouble(trans->matrix[0][2]);
+
+   matrix[1] = XFixedToDouble(trans->matrix[1][0]);
+   matrix[4] = XFixedToDouble(trans->matrix[1][1]);
+   matrix[7] = XFixedToDouble(trans->matrix[1][2]);
+
+   matrix[2] = XFixedToDouble(trans->matrix[2][0]);
+   matrix[5] = XFixedToDouble(trans->matrix[2][1]);
+   matrix[8] = XFixedToDouble(trans->matrix[2][2]);
+
+   return TRUE;
 }
 
 static void
-setup_constant_buffers(struct exa_context *exa, struct exa_pixmap_priv *pDst)
+setup_transforms(struct  exa_context *exa,
+                 PicturePtr pSrcPicture, PicturePtr pMaskPicture)
 {
-   int width = pDst->tex->width[0];
-   int height = pDst->tex->height[0];
+   PictTransform *src_t = NULL;
+   PictTransform *mask_t = NULL;
+
+   if (pSrcPicture)
+      src_t = pSrcPicture->transform;
+   if (pMaskPicture)
+      mask_t = pMaskPicture->transform;
 
-   setup_vs_constant_buffer(exa, width, height);
-   setup_fs_constant_buffer(exa);
+   exa->transform.has_src  =
+      matrix_from_pict_transform(src_t, exa->transform.src);
+   exa->transform.has_mask =
+      matrix_from_pict_transform(mask_t, exa->transform.mask);
 }
 
 boolean xorg_composite_bind_state(struct exa_context *exa,
@@ -574,17 +470,30 @@ boolean xorg_composite_bind_state(struct exa_context *exa,
                                   struct exa_pixmap_priv *pMask,
                                   struct exa_pixmap_priv *pDst)
 {
-   bind_framebuffer_state(exa, pDst);
-   bind_viewport_state(exa, pDst);
-   bind_blend_state(exa, op, pSrcPicture, pMaskPicture);
-   bind_rasterizer_state(exa);
-   bind_shaders(exa, op, pSrcPicture, pMaskPicture);
+   struct pipe_surface *dst_surf = xorg_gpu_surface(exa->scrn, pDst);
+
+   renderer_bind_destination(exa->renderer, dst_surf,
+                             pDst->width,
+                             pDst->height);
+
+   bind_blend_state(exa, op, pSrcPicture, pMaskPicture, pDstPicture);
+   bind_shaders(exa, op, pSrcPicture, pMaskPicture, pDstPicture, pSrc, pMask);
    bind_samplers(exa, op, pSrcPicture, pMaskPicture,
                  pDstPicture, pSrc, pMask, pDst);
-   bind_clip_state(exa);
-   setup_constant_buffers(exa, pDst);
 
-   return FALSE;
+   setup_transforms(exa, pSrcPicture, pMaskPicture);
+
+   if (exa->num_bound_samplers == 0 ) { /* solid fill */
+      renderer_begin_solid(exa->renderer);
+   } else {
+      renderer_begin_textures(exa->renderer,
+                              exa->bound_textures,
+                              exa->num_bound_samplers);
+   }
+
+
+   pipe_surface_reference(&dst_surf, NULL);
+   return TRUE;
 }
 
 void xorg_composite(struct exa_context *exa,
@@ -592,42 +501,25 @@ void xorg_composite(struct exa_context *exa,
                     int srcX, int srcY, int maskX, int maskY,
                     int dstX, int dstY, int width, int height)
 {
-   struct pipe_context *pipe = exa->pipe;
-   struct pipe_buffer *buf = 0;
-
    if (exa->num_bound_samplers == 0 ) { /* solid fill */
-      buf = setup_vertex_data0(exa,
-                               srcX, srcY, maskX, maskY,
-                               dstX, dstY, width, height);
-   } else if (exa->num_bound_samplers == 1 ) /* src */
-      buf = setup_vertex_data1(exa,
-                               srcX, srcY, maskX, maskY,
-                               dstX, dstY, width, height);
-   else if (exa->num_bound_samplers == 2) /* src + mask */
-      buf = setup_vertex_data2(exa,
-                               srcX, srcY, maskX, maskY,
-                               dstX, dstY, width, height);
-   else if (exa->num_bound_samplers == 3) { /* src + mask + dst */
-      debug_assert(!"src/mask/dst not handled right now");
-#if 0
-      buf = setup_vertex_data2(exa,
-                               srcX, srcY, maskX, maskY,
-                               dstX, dstY, width, height);
-#endif
-   }
-
-   if (buf) {
-      int num_attribs = 1; /*pos*/
-      num_attribs += exa->num_bound_samplers;
-      if (exa->has_solid_color)
-         ++num_attribs;
-
-      util_draw_vertex_buffer(pipe, buf, 0,
-                              PIPE_PRIM_TRIANGLE_FAN,
-                              4,  /* verts */
-                              num_attribs); /* attribs/vert */
-
-      pipe_buffer_reference(&buf, NULL);
+      renderer_solid(exa->renderer,
+                     dstX, dstY, dstX + width, dstY + height,
+                     exa->solid_color);
+   } else {
+      int pos[6] = {srcX, srcY, maskX, maskY, dstX, dstY};
+      float *src_matrix = NULL;
+      float *mask_matrix = NULL;
+
+      if (exa->transform.has_src)
+         src_matrix = exa->transform.src;
+      if (exa->transform.has_mask)
+         mask_matrix = exa->transform.mask;
+
+      renderer_texture(exa->renderer,
+                       pos, width, height,
+                       exa->bound_textures,
+                       exa->num_bound_samplers,
+                       src_matrix, mask_matrix);
    }
 }
 
@@ -635,14 +527,13 @@ boolean xorg_solid_bind_state(struct exa_context *exa,
                               struct exa_pixmap_priv *pixmap,
                               Pixel fg)
 {
+   struct pipe_surface *dst_surf = xorg_gpu_surface(exa->scrn, pixmap);
    unsigned vs_traits, fs_traits;
    struct xorg_shader shader;
 
    pixel_to_float4(fg, exa->solid_color);
    exa->has_solid_color = TRUE;
 
-   exa->solid_color[3] = 1.f;
-
 #if 0
    debug_printf("Color Pixel=(%d, %d, %d, %d), RGBA=(%f, %f, %f, %f)\n",
                 (fg >> 24) & 0xff, (fg >> 16) & 0xff,
@@ -654,17 +545,19 @@ boolean xorg_solid_bind_state(struct exa_context *exa,
    vs_traits = VS_SOLID_FILL;
    fs_traits = FS_SOLID_FILL;
 
-   bind_framebuffer_state(exa, pixmap);
-   bind_viewport_state(exa, pixmap);
-   bind_rasterizer_state(exa);
-   bind_blend_state(exa, PictOpSrc, NULL, NULL);
-   setup_constant_buffers(exa, pixmap);
-   bind_clip_state(exa);
+   renderer_bind_destination(exa->renderer, dst_surf, 
+                             pixmap->width, pixmap->height);
+   bind_blend_state(exa, PictOpSrc, NULL, NULL, NULL);
+   cso_set_samplers(exa->renderer->cso, 0, NULL);
+   cso_set_sampler_textures(exa->renderer->cso, 0, NULL);
 
-   shader = xorg_shaders_get(exa->shaders, vs_traits, fs_traits);
-   cso_set_vertex_shader_handle(exa->cso, shader.vs);
-   cso_set_fragment_shader_handle(exa->cso, shader.fs);
+   shader = xorg_shaders_get(exa->renderer->shaders, vs_traits, fs_traits);
+   cso_set_vertex_shader_handle(exa->renderer->cso, shader.vs);
+   cso_set_fragment_shader_handle(exa->renderer->cso, shader.fs);
 
+   renderer_begin_solid(exa->renderer);
+
+   pipe_surface_reference(&dst_surf, NULL);
    return TRUE;
 }
 
@@ -672,398 +565,17 @@ void xorg_solid(struct exa_context *exa,
                 struct exa_pixmap_priv *pixmap,
                 int x0, int y0, int x1, int y1)
 {
-   struct pipe_context *pipe = exa->pipe;
-   struct pipe_buffer *buf = 0;
-
-   /* 1st vertex */
-   setup_vertex0(exa->vertices2[0], x0, y0,
-                 exa->solid_color);
-   /* 2nd vertex */
-   setup_vertex0(exa->vertices2[1], x1, y0,
-                 exa->solid_color);
-   /* 3rd vertex */
-   setup_vertex0(exa->vertices2[2], x1, y1,
-                 exa->solid_color);
-   /* 4th vertex */
-   setup_vertex0(exa->vertices2[3], x0, y1,
-                 exa->solid_color);
-
-   buf = pipe_user_buffer_create(exa->pipe->screen,
-                                 exa->vertices2,
-                                 sizeof(exa->vertices2));
-
-
-   if (buf) {
-      util_draw_vertex_buffer(pipe, buf, 0,
-                              PIPE_PRIM_TRIANGLE_FAN,
-                              4,  /* verts */
-                              2); /* attribs/vert */
-
-      pipe_buffer_reference(&buf, NULL);
-   }
-}
-
-
-static INLINE void shift_rectx(float coords[4],
-                               const float *bounds,
-                               const float shift)
-{
-   coords[0] += shift;
-   coords[2] -= shift;
-   if (bounds) {
-      coords[2] = MIN2(coords[2], bounds[2]);
-      /* bound x/y + width/height */
-      if ((coords[0] + coords[2]) > (bounds[0] + bounds[2])) {
-         coords[2] = (bounds[0] + bounds[2]) - coords[0];
-      }
-   }
-}
-
-static INLINE void shift_recty(float coords[4],
-                               const float *bounds,
-                               const float shift)
-{
-   coords[1] += shift;
-   coords[3] -= shift;
-   if (bounds) {
-      coords[3] = MIN2(coords[3], bounds[3]);
-      if ((coords[1] + coords[3]) > (bounds[1] + bounds[3])) {
-         coords[3] = (bounds[1] + bounds[3]) - coords[1];
-      }
-   }
-}
-
-static INLINE void bound_rect(float coords[4],
-                              const float bounds[4],
-                              float shift[4])
-{
-   /* if outside the bounds */
-   if (coords[0] > (bounds[0] + bounds[2]) ||
-       coords[1] > (bounds[1] + bounds[3]) ||
-       (coords[0] + coords[2]) < bounds[0] ||
-       (coords[1] + coords[3]) < bounds[1]) {
-      coords[0] = 0.f;
-      coords[1] = 0.f;
-      coords[2] = 0.f;
-      coords[3] = 0.f;
-      shift[0] = 0.f;
-      shift[1] = 0.f;
-      return;
-   }
-
-   /* bound x */
-   if (coords[0] < bounds[0]) {
-      shift[0] = bounds[0] - coords[0];
-      coords[2] -= shift[0];
-      coords[0] = bounds[0];
-   } else
-      shift[0] = 0.f;
-
-   /* bound y */
-   if (coords[1] < bounds[1]) {
-      shift[1] = bounds[1] - coords[1];
-      coords[3] -= shift[1];
-      coords[1] = bounds[1];
-   } else
-      shift[1] = 0.f;
-
-   shift[2] = bounds[2] - coords[2];
-   shift[3] = bounds[3] - coords[3];
-   /* bound width/height */
-   coords[2] = MIN2(coords[2], bounds[2]);
-   coords[3] = MIN2(coords[3], bounds[3]);
-
-   /* bound x/y + width/height */
-   if ((coords[0] + coords[2]) > (bounds[0] + bounds[2])) {
-      coords[2] = (bounds[0] + bounds[2]) - coords[0];
-   }
-   if ((coords[1] + coords[3]) > (bounds[1] + bounds[3])) {
-      coords[3] = (bounds[1] + bounds[3]) - coords[1];
-   }
-
-   /* if outside the bounds */
-   if ((coords[0] + coords[2]) < bounds[0] ||
-       (coords[1] + coords[3]) < bounds[1]) {
-      coords[0] = 0.f;
-      coords[1] = 0.f;
-      coords[2] = 0.f;
-      coords[3] = 0.f;
-      return;
-   }
-}
-
-static INLINE void sync_size(float *src_loc, float *dst_loc)
-{
-   src_loc[2] = MIN2(src_loc[2], dst_loc[2]);
-   src_loc[3] = MIN2(src_loc[3], dst_loc[3]);
-   dst_loc[2] = src_loc[2];
-   dst_loc[3] = src_loc[3];
-}
-
-
-static void renderer_copy_texture(struct exa_context *exa,
-                                  struct pipe_texture *src,
-                                  float sx1, float sy1,
-                                  float sx2, float sy2,
-                                  struct pipe_texture *dst,
-                                  float dx1, float dy1,
-                                  float dx2, float dy2)
-{
-   struct pipe_context *pipe = exa->pipe;
-   struct pipe_screen *screen = pipe->screen;
-   struct pipe_buffer *buf;
-   struct pipe_surface *dst_surf = screen->get_tex_surface(
-      screen, dst, 0, 0, 0,
-      PIPE_BUFFER_USAGE_GPU_WRITE);
-   struct pipe_framebuffer_state fb;
-   float s0, t0, s1, t1;
-   struct xorg_shader shader;
-
-   assert(src->width[0] != 0);
-   assert(src->height[0] != 0);
-   assert(dst->width[0] != 0);
-   assert(dst->height[0] != 0);
-
-#if 1
-   s0 = sx1 / src->width[0];
-   s1 = sx2 / src->width[0];
-   t0 = sy1 / src->height[0];
-   t1 = sy2 / src->height[0];
-#else
-   s0 = 0;
-   s1 = 1;
-   t0 = 0;
-   t1 = 1;
-#endif
-
-#if 1
-   debug_printf("copy texture src=[%f, %f, %f, %f], dst=[%f, %f, %f, %f], tex=[%f, %f, %f, %f]\n",
-                sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2,
-                s0, t0, s1, t1);
-#endif
-
-   assert(screen->is_format_supported(screen, dst_surf->format,
-                                      PIPE_TEXTURE_2D,
-                                      PIPE_TEXTURE_USAGE_RENDER_TARGET,
-                                      0));
-
-   /* save state (restored below) */
-   cso_save_blend(exa->cso);
-   cso_save_samplers(exa->cso);
-   cso_save_sampler_textures(exa->cso);
-   cso_save_framebuffer(exa->cso);
-   cso_save_fragment_shader(exa->cso);
-   cso_save_vertex_shader(exa->cso);
-
-   cso_save_viewport(exa->cso);
-
-
-   /* set misc state we care about */
-   {
-      struct pipe_blend_state blend;
-      memset(&blend, 0, sizeof(blend));
-      blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE;
-      blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE;
-      blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
-      blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
-      blend.colormask = PIPE_MASK_RGBA;
-      cso_set_blend(exa->cso, &blend);
-   }
-
-   /* sampler */
-   {
-      struct pipe_sampler_state sampler;
-      memset(&sampler, 0, sizeof(sampler));
-      sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
-      sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
-      sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
-      sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
-      sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
-      sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
-      sampler.normalized_coords = 1;
-      cso_single_sampler(exa->cso, 0, &sampler);
-      cso_single_sampler_done(exa->cso);
-   }
-
-   set_viewport(exa, dst_surf->width, dst_surf->height, Y0_TOP);
-
-   /* texture */
-   cso_set_sampler_textures(exa->cso, 1, &src);
-
-   /* shaders */
-   shader = xorg_shaders_get(exa->shaders,
-                             VS_COMPOSITE,
-                             FS_COMPOSITE);
-   cso_set_vertex_shader_handle(exa->cso, shader.vs);
-   cso_set_fragment_shader_handle(exa->cso, shader.fs);
-
-   /* drawing dest */
-   memset(&fb, 0, sizeof(fb));
-   fb.width = dst_surf->width;
-   fb.height = dst_surf->height;
-   fb.nr_cbufs = 1;
-   fb.cbufs[0] = dst_surf;
-   {
-      int i;
-      for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i)
-         fb.cbufs[i] = 0;
-   }
-   cso_set_framebuffer(exa->cso, &fb);
-   setup_vs_constant_buffer(exa, fb.width, fb.height);
-   setup_fs_constant_buffer(exa);
-
-   /* draw quad */
-   buf = setup_vertex_data_tex(exa,
-                               dx1, dy1,
-                               dx2, dy2,
-                               s0, t0, s1, t1,
-                               0.0f);
-
-   if (buf) {
-      util_draw_vertex_buffer(exa->pipe, buf, 0,
-                              PIPE_PRIM_TRIANGLE_FAN,
-                              4,  /* verts */
-                              2); /* attribs/vert */
-
-      pipe_buffer_reference(&buf, NULL);
-   }
-
-   /* restore state we changed */
-   cso_restore_blend(exa->cso);
-   cso_restore_samplers(exa->cso);
-   cso_restore_sampler_textures(exa->cso);
-   cso_restore_framebuffer(exa->cso);
-   cso_restore_vertex_shader(exa->cso);
-   cso_restore_fragment_shader(exa->cso);
-   cso_restore_viewport(exa->cso);
-
-   pipe_surface_reference(&dst_surf, NULL);
+   renderer_solid(exa->renderer,
+                  x0, y0, x1, y1, exa->solid_color);
 }
 
-
-static struct pipe_texture *
-create_sampler_texture(struct exa_context *ctx,
-                       struct pipe_texture *src)
+void
+xorg_composite_done(struct exa_context *exa)
 {
-   enum pipe_format format;
-   struct pipe_context *pipe = ctx->pipe;
-   struct pipe_screen *screen = pipe->screen;
-   struct pipe_texture *pt;
-   struct pipe_texture templ;
-
-   pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
-
-   /* the coming in texture should already have that invariance */
-   debug_assert(screen->is_format_supported(screen, src->format,
-                                            PIPE_TEXTURE_2D,
-                                            PIPE_TEXTURE_USAGE_SAMPLER, 0));
-
-   format = src->format;
-
-   memset(&templ, 0, sizeof(templ));
-   templ.target = PIPE_TEXTURE_2D;
-   templ.format = format;
-   templ.last_level = 0;
-   templ.width[0] = src->width[0];
-   templ.height[0] = src->height[0];
-   templ.depth[0] = 1;
-   pf_get_block(format, &templ.block);
-   templ.tex_usage = PIPE_TEXTURE_USAGE_SAMPLER;
-
-   pt = screen->texture_create(screen, &templ);
-
-   debug_assert(!pt || pipe_is_referenced(&pt->reference));
-
-   if (!pt)
-      return NULL;
-
-   {
-      /* copy source framebuffer surface into texture */
-      struct pipe_surface *ps_read = screen->get_tex_surface(
-         screen, src, 0, 0, 0, PIPE_BUFFER_USAGE_GPU_READ);
-      struct pipe_surface *ps_tex = screen->get_tex_surface(
-         screen, pt, 0, 0, 0, PIPE_BUFFER_USAGE_GPU_WRITE );
-      pipe->surface_copy(pipe,
-                        ps_tex, /* dest */
-                        0, 0, /* destx/y */
-                        ps_read,
-                        0, 0, src->width[0], src->height[0]);
-      pipe_surface_reference(&ps_read, NULL);
-      pipe_surface_reference(&ps_tex, NULL);
-   }
-
-   return pt;
-}
+   renderer_draw_flush(exa->renderer);
 
-void xorg_copy_pixmap(struct exa_context *ctx,
-                      struct exa_pixmap_priv *dst_priv, int dx, int dy,
-                      struct exa_pixmap_priv *src_priv, int sx, int sy,
-                      int width, int height)
-{
-   float dst_loc[4], src_loc[4];
-   float dst_bounds[4], src_bounds[4];
-   float src_shift[4], dst_shift[4], shift[4];
-   struct pipe_texture *dst = dst_priv->tex;
-   struct pipe_texture *src = src_priv->tex;
-
-   xorg_exa_finish(ctx);
-
-   dst_loc[0] = dx;
-   dst_loc[1] = dy;
-   dst_loc[2] = width;
-   dst_loc[3] = height;
-   dst_bounds[0] = 0.f;
-   dst_bounds[1] = 0.f;
-   dst_bounds[2] = dst->width[0];
-   dst_bounds[3] = dst->height[0];
-
-   src_loc[0] = sx;
-   src_loc[1] = sy;
-   src_loc[2] = width;
-   src_loc[3] = height;
-   src_bounds[0] = 0.f;
-   src_bounds[1] = 0.f;
-   src_bounds[2] = src->width[0];
-   src_bounds[3] = src->height[0];
-
-   bound_rect(src_loc, src_bounds, src_shift);
-   bound_rect(dst_loc, dst_bounds, dst_shift);
-   shift[0] = src_shift[0] - dst_shift[0];
-   shift[1] = src_shift[1] - dst_shift[1];
-
-   if (shift[0] < 0)
-      shift_rectx(src_loc, src_bounds, -shift[0]);
-   else
-      shift_rectx(dst_loc, dst_bounds, shift[0]);
-
-   if (shift[1] < 0)
-      shift_recty(src_loc, src_bounds, -shift[1]);
-   else
-      shift_recty(dst_loc, dst_bounds, shift[1]);
-
-   sync_size(src_loc, dst_loc);
-
-   if (src_loc[2] >= 0 && src_loc[3] >= 0 &&
-       dst_loc[2] >= 0 && dst_loc[3] >= 0) {
-      struct pipe_texture *temp_src = src;
-
-      if (src == dst)
-         temp_src = create_sampler_texture(ctx, src);
-
-      renderer_copy_texture(ctx,
-                            temp_src,
-                            src_loc[0],
-                            src_loc[1],
-                            src_loc[0] + src_loc[2],
-                            src_loc[1] + src_loc[3],
-                            dst,
-                            dst_loc[0],
-                            dst_loc[1],
-                            dst_loc[0] + dst_loc[2],
-                            dst_loc[1] + dst_loc[3]);
-
-      if (src == dst)
-         pipe_texture_reference(&temp_src, NULL);
-   }
+   exa->transform.has_src = FALSE;
+   exa->transform.has_mask = FALSE;
+   exa->has_solid_color = FALSE;
+   exa->num_bound_samplers = 0;
 }
-