st/xorg: implement basic src/mask transformations
authorZack Rusin <zackr@vmware.com>
Tue, 13 Oct 2009 17:06:39 +0000 (13:06 -0400)
committerZack Rusin <zackr@vmware.com>
Tue, 20 Oct 2009 03:45:31 +0000 (23:45 -0400)
plus fix filters

src/gallium/state_trackers/xorg/Makefile
src/gallium/state_trackers/xorg/xorg_composite.c
src/gallium/state_trackers/xorg/xorg_exa.c
src/gallium/state_trackers/xorg/xorg_exa.h
src/gallium/state_trackers/xorg/xorg_renderer.c
src/gallium/state_trackers/xorg/xorg_renderer.h

index 27a1990724d4cfa220091a2afa3a56608ebfefe7..030bac5fff2f74fbad933d822c48fb99c9e15d29 100644 (file)
@@ -5,6 +5,7 @@ LIBNAME = xorgtracker
 
 LIBRARY_INCLUDES = \
        -DHAVE_CONFIG_H \
+        -DHAVE_XEXTPROTO_71=1 \
        $(shell pkg-config --cflags-only-I pixman-1 xorg-server libdrm xproto) \
        -I$(TOP)/src/gallium/include \
        -I$(TOP)/src/gallium/auxiliary \
index d6483fb72c4203b3ff0dcdd7d74ea0be612860e4..7379e3b74615dd79d8c1c9f766661f8a8f503fe6 100644 (file)
@@ -9,6 +9,9 @@
 
 #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;
 
@@ -144,6 +147,43 @@ 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;
+   default:
+      debug_printf("Unkown xrender filter");
+      *out_filter = PIPE_TEX_FILTER_NEAREST;
+      return FALSE;
+   }
+
+   return TRUE;
+}
+
+static boolean is_filter_accelerated(PicturePtr pic)
+{
+   int filter;
+   if (pic && !render_filter_to_gallium(pic->filter, &filter))
+       return FALSE;
+   return TRUE;
+}
+
 boolean xorg_composite_accelerated(int op,
                                    PicturePtr pSrcPicture,
                                    PicturePtr pMaskPicture,
@@ -156,6 +196,11 @@ boolean xorg_composite_accelerated(int op,
    unsigned accel_ops_count =
       sizeof(accelerated_ops)/sizeof(struct acceleration_info);
 
+   if (!is_filter_accelerated(pSrcPicture) ||
+       !is_filter_accelerated(pMaskPicture)) {
+      XORG_FALLBACK("Unsupported Xrender filter");
+   }
+
    if (pSrcPicture->pSourcePict) {
       if (pSrcPicture->pSourcePict->type != SourcePictTypeSolidFill)
          XORG_FALLBACK("gradients not enabled (haven't been well tested)");
@@ -163,13 +208,10 @@ boolean xorg_composite_accelerated(int op,
 
    for (i = 0; i < accel_ops_count; ++i) {
       if (op == accelerated_ops[i].op) {
-         /* Check for unsupported component alpha */
-         if ((pSrcPicture->componentAlpha &&
-              !accelerated_ops[i].component_alpha) ||
-             (pMaskPicture &&
-              (!accelerated_ops[i].with_mask ||
-               (pMaskPicture->componentAlpha &&
-                !accelerated_ops[i].component_alpha))))
+         /* Check for component alpha */
+         if (pMaskPicture &&
+             (pMaskPicture->componentAlpha ||
+              (!accelerated_ops[i].with_mask)))
             XORG_FALLBACK("component alpha unsupported (PictOpOver=%s(%d)",
                           (accelerated_ops[i].op == PictOpOver) ? "yes" : "no",
                           accelerated_ops[i].op);
@@ -238,7 +280,6 @@ bind_shaders(struct exa_context *exa, int op,
    cso_set_fragment_shader_handle(exa->renderer->cso, shader.fs);
 }
 
-
 static void
 bind_samplers(struct exa_context *exa, int op,
               PicturePtr pSrcPicture, PicturePtr pMaskPicture,
@@ -264,10 +305,15 @@ bind_samplers(struct exa_context *exa, int op,
    if (pSrcPicture && pSrc) {
       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 = PIPE_TEX_MIPFILTER_NEAREST;
-      src_sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
+      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;
@@ -277,10 +323,15 @@ bind_samplers(struct exa_context *exa, int op,
    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;
@@ -328,6 +379,44 @@ setup_constant_buffers(struct exa_context *exa, struct exa_pixmap_priv *pDst)
    setup_fs_constant_buffer(exa);
 }
 
+static INLINE boolean matrix_from_pict_transform(PictTransform *trans, float *matrix)
+{
+   if (!trans)
+      return FALSE;
+
+   matrix[0] = XFixedToDouble(trans->matrix[0][0]);
+   matrix[1] = XFixedToDouble(trans->matrix[0][1]);
+   matrix[2] = XFixedToDouble(trans->matrix[0][2]);
+
+   matrix[3] = XFixedToDouble(trans->matrix[1][0]);
+   matrix[4] = XFixedToDouble(trans->matrix[1][1]);
+   matrix[5] = XFixedToDouble(trans->matrix[1][2]);
+
+   matrix[6] = XFixedToDouble(trans->matrix[2][0]);
+   matrix[7] = XFixedToDouble(trans->matrix[2][1]);
+   matrix[8] = XFixedToDouble(trans->matrix[2][2]);
+
+   return TRUE;
+}
+
+static void
+setup_transforms(struct  exa_context *exa,
+                 PicturePtr pSrcPicture, PicturePtr pMaskPicture)
+{
+   PictTransform *src_t = NULL;
+   PictTransform *mask_t = NULL;
+
+   if (pSrcPicture)
+      src_t = pSrcPicture->transform;
+   if (pMaskPicture)
+      mask_t = pMaskPicture->transform;
+
+   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,
                                   int op,
                                   PicturePtr pSrcPicture,
@@ -346,6 +435,8 @@ boolean xorg_composite_bind_state(struct exa_context *exa,
                  pDstPicture, pSrc, pMask, pDst);
    setup_constant_buffers(exa, pDst);
 
+   setup_transforms(exa, pSrcPicture, pMaskPicture);
+
    return TRUE;
 }
 
@@ -360,10 +451,19 @@ void xorg_composite(struct exa_context *exa,
                                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_draw_textures(exa->renderer,
                              pos, width, height,
                              exa->bound_textures,
-                             exa->num_bound_samplers);
+                             exa->num_bound_samplers,
+                             src_matrix, mask_matrix);
    }
 }
 
index ca25d905579d30b96156b5ad5e7e215b6a743788..39c4d26ebe8acc07997e484f75b426557434b129 100644 (file)
@@ -92,6 +92,8 @@ xorg_exa_common_done(struct exa_context *exa)
 {
    exa->copy.src = NULL;
    exa->copy.dst = NULL;
+   exa->transform.has_src = FALSE;
+   exa->transform.has_mask = FALSE;
    exa->has_solid_color = FALSE;
    exa->num_bound_samplers = 0;
 }
index 292f964cec68a8951a51ad492ec38b46a1fe8a49..45f88d94048fb73f8d88416182496bc5adf5cb3e 100644 (file)
@@ -24,6 +24,14 @@ struct exa_context
    float solid_color[4];
    boolean has_solid_color;
 
+   /* float[9] projective matrix bound to pictures */
+   struct {
+      float    src[9];
+      float   mask[9];
+      boolean has_src;
+      boolean has_mask;
+   } transform;
+
    struct {
       struct exa_pixmap_priv *src;
       struct exa_pixmap_priv *dst;
index ca69e1e0e92f129f7ddb21fd90142500e6a554e3..3dd5e6e811d2dcd145e5736abcf542796e0d8a9f 100644 (file)
 
 #include "pipe/p_inlines.h"
 
+#include <math.h>
+
 enum AxisOrientation {
    Y0_BOTTOM,
    Y0_TOP
 };
 
+#define floatsEqual(x, y) (fabs(x - y) <= 0.00001f * MIN2(fabs(x), fabs(y)))
+#define floatIsZero(x) (floatsEqual((x) + 1, 1))
+
+static INLINE boolean is_affine(float *matrix)
+{
+   return floatIsZero(matrix[2]) && floatIsZero(matrix[5])
+      && floatsEqual(matrix[8], 1);
+}
+static INLINE void map_point(float *mat, float x, float y,
+                             float *out_x, float *out_y)
+{
+   if (!mat) {
+      *out_x = x;
+      *out_y = y;
+      return;
+   }
+
+   *out_x = mat[0]*x + mat[3]*y + mat[6];
+   *out_y = mat[1]*x + mat[4]*y + mat[7];
+   if (!is_affine(mat)) {
+      float w = 1/(mat[2]*x + mat[5]*y + mat[8]);
+      *out_x *= w;
+      *out_y *= w;
+   }
+}
+
 static void
 renderer_init_state(struct xorg_renderer *r)
 {
@@ -60,23 +88,38 @@ static struct pipe_buffer *
 setup_vertex_data1(struct xorg_renderer *r,
                    int srcX, int srcY,  int dstX, int dstY,
                    int width, int height,
-                   struct pipe_texture *src)
+                   struct pipe_texture *src, float *src_matrix)
 {
-   float s0, t0, s1, t1;
+   float s0, t0, s1, t1, stmp, ttmp;
 
    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(r->vertices2[0], dstX, dstY, s0, t0);
-   /* 2nd vertex */
-   setup_vertex1(r->vertices2[1], dstX + width, dstY, s1, t0);
-   /* 3rd vertex */
-   setup_vertex1(r->vertices2[2], dstX + width, dstY + height, s1, t1);
-   /* 4th vertex */
-   setup_vertex1(r->vertices2[3], dstX, dstY + height, s0, t1);
+   if (src_matrix) {
+      /* 1st vertex */
+      map_point(src_matrix, s0, t0, &stmp, &ttmp);
+      setup_vertex1(r->vertices2[0], dstX, dstY, stmp, ttmp);
+      /* 2nd vertex */
+      map_point(src_matrix, s1, t0, &stmp, &ttmp);
+      setup_vertex1(r->vertices2[1], dstX + width, dstY, stmp, ttmp);
+      /* 3rd vertex */
+      map_point(src_matrix, s1, t1, &stmp, &ttmp);
+      setup_vertex1(r->vertices2[2], dstX + width, dstY + height, stmp, ttmp);
+      /* 4th vertex */
+      map_point(src_matrix, s0, t1, &stmp, &ttmp);
+      setup_vertex1(r->vertices2[3], dstX, dstY + height, stmp, ttmp);
+   } else {
+      /* 1st vertex */
+      setup_vertex1(r->vertices2[0], dstX, dstY, s0, t0);
+      /* 2nd vertex */
+      setup_vertex1(r->vertices2[1], dstX + width, dstY, s1, t0);
+      /* 3rd vertex */
+      setup_vertex1(r->vertices2[2], dstX + width, dstY + height, s1, t1);
+      /* 4th vertex */
+      setup_vertex1(r->vertices2[3], dstX, dstY + height, s0, t1);
+   }
 
    return pipe_user_buffer_create(r->pipe->screen,
                                   r->vertices2,
@@ -128,9 +171,11 @@ setup_vertex_data2(struct xorg_renderer *r,
                    int srcX, int srcY, int maskX, int maskY,
                    int dstX, int dstY, int width, int height,
                    struct pipe_texture *src,
-                   struct pipe_texture *mask)
+                   struct pipe_texture *mask,
+                   float *src_matrix, float *mask_matrix)
 {
    float st0[4], st1[4];
+   float pt0[2], pt1[2];
 
    st0[0] = srcX / src->width[0];
    st0[1] = srcY / src->height[0];
@@ -142,18 +187,49 @@ setup_vertex_data2(struct xorg_renderer *r,
    st1[2] = maskX + width / mask->width[0];
    st1[3] = maskY + height / mask->height[0];
 
-   /* 1st vertex */
-   setup_vertex2(r->vertices3[0], dstX, dstY,
-                 st0[0], st0[1], st1[0], st1[1]);
-   /* 2nd vertex */
-   setup_vertex2(r->vertices3[1], dstX + width, dstY,
-                 st0[2], st0[1], st1[2], st1[1]);
-   /* 3rd vertex */
-   setup_vertex2(r->vertices3[2], dstX + width, dstY + height,
-                 st0[2], st0[3], st1[2], st1[3]);
-   /* 4th vertex */
-   setup_vertex2(r->vertices3[3], dstX, dstY + height,
-                 st0[0], st0[3], st1[0], st1[3]);
+   if (src_matrix || mask_matrix) {
+      /* 1st vertex */
+      map_point(src_matrix, st0[0], st0[1],
+                pt0 + 0, pt0 + 1);
+      map_point(mask_matrix, st1[0], st1[1],
+                pt1 + 0, pt1 + 1);
+      setup_vertex2(r->vertices3[0], dstX, dstY,
+                    pt0[0], pt0[1], pt1[0], pt1[1]);
+      /* 2nd vertex */
+      map_point(src_matrix, st0[2], st0[1],
+                pt0 + 0, pt0 + 1);
+      map_point(mask_matrix, st1[2], st1[1],
+                pt1 + 0, pt1 + 1);
+      setup_vertex2(r->vertices3[1], dstX + width, dstY,
+                    pt0[0], pt0[1], pt1[0], pt1[1]);
+      /* 3rd vertex */
+      map_point(src_matrix, st0[2], st0[3],
+                pt0 + 0, pt0 + 1);
+      map_point(mask_matrix, st1[2], st1[3],
+                pt1 + 0, pt1 + 1);
+      setup_vertex2(r->vertices3[2], dstX + width, dstY + height,
+                    pt0[0], pt0[1], pt1[0], pt1[1]);
+      /* 4th vertex */
+      map_point(src_matrix, st0[0], st0[3],
+                pt0 + 0, pt0 + 1);
+      map_point(mask_matrix, st1[0], st1[3],
+                pt1 + 0, pt1 + 1);
+      setup_vertex2(r->vertices3[3], dstX, dstY + height,
+                    pt0[0], pt0[1], pt1[0], pt1[1]);
+   } else {
+      /* 1st vertex */
+      setup_vertex2(r->vertices3[0], dstX, dstY,
+                    st0[0], st0[1], st1[0], st1[1]);
+      /* 2nd vertex */
+      setup_vertex2(r->vertices3[1], dstX + width, dstY,
+                    st0[2], st0[1], st1[2], st1[1]);
+      /* 3rd vertex */
+      setup_vertex2(r->vertices3[2], dstX + width, dstY + height,
+                    st0[2], st0[3], st1[2], st1[3]);
+      /* 4th vertex */
+      setup_vertex2(r->vertices3[3], dstX, dstY + height,
+                    st0[0], st0[3], st1[0], st1[3]);
+   }
 
    return pipe_user_buffer_create(r->pipe->screen,
                                   r->vertices3,
@@ -721,7 +797,8 @@ void renderer_draw_textures(struct xorg_renderer *r,
                             int *pos,
                             int width, int height,
                             struct pipe_texture **textures,
-                            int num_textures)
+                            int num_textures,
+                            float *src_matrix, float *mask_matrix)
 {
    struct pipe_context *pipe = r->pipe;
    struct pipe_buffer *buf = 0;
@@ -732,7 +809,7 @@ void renderer_draw_textures(struct xorg_renderer *r,
                                pos[0], pos[1], /* src */
                                pos[4], pos[5], /* dst */
                                width, height,
-                               textures[0]);
+                               textures[0], src_matrix);
       break;
    case 2:
       buf = setup_vertex_data2(r,
@@ -740,7 +817,8 @@ void renderer_draw_textures(struct xorg_renderer *r,
                                pos[2], pos[3], /* mask */
                                pos[4], pos[5], /* dst */
                                width, height,
-                               textures[0], textures[1]);
+                               textures[0], textures[1],
+                               src_matrix, mask_matrix);
       break;
    default:
       debug_assert(!"Unsupported number of textures");
index b6296d5fd6b8fd579ebc0cba5ff0c518dcaa429a..3e37c9aa9301bb3004bb7c2b9ba4a16891343858 100644 (file)
@@ -47,7 +47,9 @@ void renderer_draw_textures(struct xorg_renderer *r,
                             int *pos,
                             int width, int height,
                             struct pipe_texture **textures,
-                            int num_textures);
+                            int num_textures,
+                            float *src_matrix,
+                            float *mask_matrix);
 
 
 #endif