Mesa (master): st/xorg: implement basic src/mask transformations

Zack Rusin zack at kemper.freedesktop.org
Tue Oct 20 03:38:54 UTC 2009


Module: Mesa
Branch: master
Commit: a39a3cc14e816cc91a81028a27c4dbd4816cdc9d
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=a39a3cc14e816cc91a81028a27c4dbd4816cdc9d

Author: Zack Rusin <zackr at vmware.com>
Date:   Tue Oct 13 13:06:39 2009 -0400

st/xorg: implement basic src/mask transformations

plus fix filters

---

 src/gallium/state_trackers/xorg/Makefile         |    1 +
 src/gallium/state_trackers/xorg/xorg_composite.c |  126 +++++++++++++++++++--
 src/gallium/state_trackers/xorg/xorg_exa.c       |    2 +
 src/gallium/state_trackers/xorg/xorg_exa.h       |    8 ++
 src/gallium/state_trackers/xorg/xorg_renderer.c  |  130 +++++++++++++++++-----
 src/gallium/state_trackers/xorg/xorg_renderer.h  |    4 +-
 6 files changed, 231 insertions(+), 40 deletions(-)

diff --git a/src/gallium/state_trackers/xorg/Makefile b/src/gallium/state_trackers/xorg/Makefile
index 27a1990..030bac5 100644
--- a/src/gallium/state_trackers/xorg/Makefile
+++ b/src/gallium/state_trackers/xorg/Makefile
@@ -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 \
diff --git a/src/gallium/state_trackers/xorg/xorg_composite.c b/src/gallium/state_trackers/xorg/xorg_composite.c
index d6483fb..7379e3b 100644
--- a/src/gallium/state_trackers/xorg/xorg_composite.c
+++ b/src/gallium/state_trackers/xorg/xorg_composite.c
@@ -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);
    }
 }
 
diff --git a/src/gallium/state_trackers/xorg/xorg_exa.c b/src/gallium/state_trackers/xorg/xorg_exa.c
index ca25d90..39c4d26 100644
--- a/src/gallium/state_trackers/xorg/xorg_exa.c
+++ b/src/gallium/state_trackers/xorg/xorg_exa.c
@@ -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;
 }
diff --git a/src/gallium/state_trackers/xorg/xorg_exa.h b/src/gallium/state_trackers/xorg/xorg_exa.h
index 292f964..45f88d9 100644
--- a/src/gallium/state_trackers/xorg/xorg_exa.h
+++ b/src/gallium/state_trackers/xorg/xorg_exa.h
@@ -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;
diff --git a/src/gallium/state_trackers/xorg/xorg_renderer.c b/src/gallium/state_trackers/xorg/xorg_renderer.c
index ca69e1e..3dd5e6e 100644
--- a/src/gallium/state_trackers/xorg/xorg_renderer.c
+++ b/src/gallium/state_trackers/xorg/xorg_renderer.c
@@ -11,11 +11,39 @@
 
 #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");
diff --git a/src/gallium/state_trackers/xorg/xorg_renderer.h b/src/gallium/state_trackers/xorg/xorg_renderer.h
index b6296d5..3e37c9a 100644
--- a/src/gallium/state_trackers/xorg/xorg_renderer.h
+++ b/src/gallium/state_trackers/xorg/xorg_renderer.h
@@ -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




More information about the mesa-commit mailing list