vmwgfx: Support xa composite.
authorThomas Hellstrom <thellstrom@vmware.com>
Wed, 22 Jun 2011 20:26:20 +0000 (22:26 +0200)
committerThomas Hellstrom <thellstrom@vmware.com>
Fri, 1 Jul 2011 09:35:32 +0000 (11:35 +0200)
Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
vmwgfx/Makefile.am
vmwgfx/vmwgfx_saa.c
vmwgfx/vmwgfx_saa.h
vmwgfx/vmwgfx_xa_composite.c [new file with mode: 0644]

index 3c31543..03dbf6a 100644 (file)
@@ -20,6 +20,7 @@ vmwgfx_drv_la_SOURCES = \
        vmwgfx_overlay.c \
        vmwgfx_ctrl.c \
        vmwgfx_ctrl.h \
+       vmwgfx_xa_composite.c \
        wsbm_util.h
 
 
index 297e1f3..48c327d 100644 (file)
@@ -33,7 +33,6 @@
 #include "vmwgfx_saa.h"
 #include "vmwgfx_drmi.h"
 
-
 #define VMWGFX_PIX_MALLOC  (1 << 0)
 #define VMWGFX_PIX_GMR     (1 << 1)
 #define VMWGFX_PIX_SURFACE (1 << 2)
@@ -56,6 +55,7 @@ struct vmwgfx_saa {
     Bool can_optimize_dma;
     void (*present_flush) (ScreenPtr pScreen);
     struct _WsbmListHead sync_x_list;
+    struct vmwgfx_composite *vcomp;
 };
 
 static inline struct vmwgfx_saa *
@@ -277,13 +277,6 @@ vmwgfx_pixmap_present_readback(struct vmwgfx_saa *vsaa,
        return TRUE;
 
     /*
-     * Flush dirty stuff to screen.
-     */
-
-
-    vsaa->present_flush(vsaa->pScreen);
-
-    /*
      * Intersect dirty region with region to be read back, if any.
      */
 
@@ -1014,11 +1007,141 @@ vmwgfx_copy_done(struct saa_driver *driver)
     xa_copy_done(vsaa->xa_ctx);
 }
 
+static Bool
+vmwgfx_composite_prepare(struct saa_driver *driver, CARD8 op,
+                        PicturePtr src_pict, PicturePtr mask_pict,
+                        PicturePtr dst_pict,
+                        PixmapPtr src_pix, PixmapPtr mask_pix,
+                        PixmapPtr dst_pix,
+                        RegionPtr src_region,
+                        RegionPtr mask_region,
+                        RegionPtr dst_region)
+{
+    struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
+    struct vmwgfx_saa_pixmap *src_vpix;
+    struct vmwgfx_saa_pixmap *dst_vpix;
+    struct vmwgfx_saa_pixmap *mask_vpix;
+    Bool tmp_valid_hw;
+    Bool dirty_hw;
+    Bool valid_hw;
+    RegionRec empty;
+    struct xa_composite *xa_comp;
+
+    REGION_NULL(pScreen, &empty);
+
+    /*
+     * First we define our migration policy. We accelerate only if there
+     * is dirty hw regions to be read or if all source data is
+     * available in hw, and the destination has a hardware surface.
+     */
+
+    dst_vpix = vmwgfx_saa_pixmap(dst_pix);
+    valid_hw = (dst_vpix->hw != NULL);
+    if (saa_op_reads_destination(op)) {
+       vmwgfx_check_hw_contents(vsaa, dst_vpix, dst_region,
+                                &dirty_hw, &tmp_valid_hw);
+       valid_hw = (valid_hw && tmp_valid_hw);
+    } else {
+       dirty_hw = FALSE;
+       dst_region = &empty;
+    }
+
+    if (src_pix && !dirty_hw) {
+       src_vpix = vmwgfx_saa_pixmap(src_pix);
+       vmwgfx_check_hw_contents(vsaa, src_vpix, src_region,
+                                &dirty_hw, &tmp_valid_hw);
+       valid_hw = (valid_hw && tmp_valid_hw);
+    }
+
+    if (mask_pict && mask_pix && !dirty_hw) {
+       mask_vpix = vmwgfx_saa_pixmap(mask_pix);
+       vmwgfx_check_hw_contents(vsaa, mask_vpix, mask_region,
+                                &dirty_hw, &tmp_valid_hw);
+       valid_hw = (valid_hw && tmp_valid_hw);
+    }
+
+    if (!valid_hw && !dirty_hw)
+       goto out_err;
+
+    /*
+     * Then, setup most of the XA composite state (except hardware surfaces)
+     * and check whether XA can accelerate.
+     */
+
+    xa_comp = vmwgfx_xa_setup_comp(vsaa->vcomp, op,
+                                  src_pict, mask_pict, dst_pict);
+    if (!xa_comp)
+       goto out_err;
+
+    if (xa_composite_check_accelerated(xa_comp) != XA_ERR_NONE)
+       goto out_err;
+
+    /*
+     * Create hw surfaces and migrate data needed for HW compositing.
+     */
+
+    if (src_region == NULL)
+       src_region = &empty;
+    if (src_pix &&
+       !vmwgfx_pixmap_validate_hw(src_pix, src_region, 0, 0, 0))
+       goto out_err;
+
+    if (mask_region == NULL)
+       mask_region = &empty;
+    if (mask_pict && mask_pix &&
+       !vmwgfx_pixmap_validate_hw(mask_pix, mask_region, 0, 0, 0))
+       goto out_err;
+
+    if (dst_region == NULL)
+       dst_region = &empty;
+    if (!vmwgfx_pixmap_validate_hw(dst_pix, dst_region, 0, 0, 0))
+       goto out_err;
+
+    /*
+     * Update the XA state with our hardware surfaces and
+     * surface formats, and bind the XA state for compositing.
+     */
+
+    if (!vmwgfx_xa_update_comp(xa_comp, src_pix, mask_pix, dst_pix))
+       goto out_err;
+
+    if (xa_composite_prepare(vsaa->xa_ctx, xa_comp))
+       goto out_err;
+
+    REGION_UNINIT(pScreen, &empty);
+    return TRUE;
+ out_err:
+    REGION_UNINIT(pScreen, &empty);
+    return FALSE;
+}
+
+static void
+vmwgfx_composite(struct saa_driver *driver,
+                int src_x, int src_y, int mask_x, int mask_y,
+                int dst_x, int dst_y,
+                int width, int height)
+{
+    struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
+
+    xa_composite_rect(vsaa->xa_ctx, src_x, src_y, mask_x, mask_y,
+                     dst_x, dst_y, width, height);
+}
+
+static void
+vmwgfx_composite_done(struct saa_driver *driver)
+{
+   struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
+
+   xa_composite_done(vsaa->xa_ctx);
+}
+
 static void
 vmwgfx_takedown(struct saa_driver *driver)
 {
     struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
 
+    if (vsaa->vcomp)
+       vmwgfx_free_composite(vsaa->vcomp);
     free(vsaa);
 }
 
@@ -1130,6 +1253,9 @@ static const struct saa_driver vmwgfx_saa_driver = {
     .copy_prepare = vmwgfx_copy_prepare,
     .copy = vmwgfx_copy,
     .copy_done = vmwgfx_copy_done,
+    .composite_prepare = vmwgfx_composite_prepare,
+    .composite = vmwgfx_composite,
+    .composite_done = vmwgfx_composite_done,
     .takedown = vmwgfx_takedown,
 };
 
@@ -1154,6 +1280,11 @@ vmwgfx_saa_init(ScreenPtr pScreen, int drm_fd, struct xa_tracker *xat,
     WSBMINITLISTHEAD(&vsaa->sync_x_list);
 
     vsaa->driver = vmwgfx_saa_driver;
+    vsaa->vcomp = vmwgfx_alloc_composite();
+
+    if (!vsaa->vcomp)
+       vsaa->driver.composite_prepare = NULL;
+
     if (!saa_driver_init(pScreen, &vsaa->driver))
        goto out_no_saa;
 
index 29863c5..deb3f37 100644 (file)
 #define _VMWGFX_SAA_H_
 
 #include "saa.h"
-#include <xa_tracker.h>
+#include <xa_composite.h>
 #include "vmwgfx_drmi.h"
 #include "wsbm_util.h"
 
+
 #define VMWGFX_FLAG_FORCE_GMR     (1 << 0) /* Create with GMR as backing store */
 #define VMWGFX_FLAG_FORCE_SURFACE (1 << 1) /* Create with surface as backing store */
 #define VMWGFX_FLAG_AVOID_HWACCEL (1 << 2) /* Avoid Hardware acceleration on this pixmap */
@@ -98,4 +99,28 @@ vmwgfx_remove_dri2_list(struct vmwgfx_saa_pixmap *vpix);
 extern void
 vmwgfx_flush_dri2(ScreenPtr pScreen);
 
+/*
+ * vmwgfx_xa_composite.c
+ */
+
+struct vmwgfx_composite;
+
+void
+vmwgfx_free_composite(struct vmwgfx_composite *vcomp);
+struct vmwgfx_composite *
+vmwgfx_alloc_composite(void);
+
+Bool
+vmwgfx_xa_update_comp(struct xa_composite *comp,
+                     PixmapPtr src_pix,
+                     PixmapPtr mask_pix,
+                     PixmapPtr dst_pix);
+
+struct xa_composite *
+vmwgfx_xa_setup_comp(struct vmwgfx_composite *vcomp,
+                    int op,
+                    PicturePtr src_pict,
+                    PicturePtr mask_pict,
+                    PicturePtr dst_pict);
+
 #endif
diff --git a/vmwgfx/vmwgfx_xa_composite.c b/vmwgfx/vmwgfx_xa_composite.c
new file mode 100644 (file)
index 0000000..a2e3970
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ * Copyright 2009-2011 VMWare, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Thomas Hellstrom <thellstrom@vmware.com>
+ * Author: Zack Ruzin <zackr@vmware.com>
+ *
+ * The code in this file translates XRender PICT composite stuff
+ * to fit the libxatracker API.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <picturestr.h>
+#include <X11/extensions/Xrender.h>
+#include "xa_composite.h"
+#include "vmwgfx_saa.h"
+#include "vmwgfx_saa_priv.h"
+
+
+struct vmwgfx_composite {
+    union xa_source_pict *src_spict;
+    union xa_source_pict *mask_spict;
+    union xa_source_pict *dst_spict;
+    struct xa_picture *src_pict;
+    struct xa_picture *mask_pict;
+    struct xa_picture *dst_pict;
+    struct xa_composite *comp;
+};
+
+static const enum xa_composite_op vmwgfx_op_map[] = {
+    [PictOpClear] = xa_op_clear,
+    [PictOpSrc] = xa_op_src,
+    [PictOpDst] = xa_op_dst,
+    [PictOpOver] = xa_op_over,
+    [PictOpOverReverse] = xa_op_over_reverse,
+    [PictOpIn] = xa_op_in,
+    [PictOpInReverse] = xa_op_in_reverse,
+    [PictOpOut] = xa_op_out,
+    [PictOpOutReverse] = xa_op_out_reverse,
+    [PictOpAtop] = xa_op_atop,
+    [PictOpAtopReverse] = xa_op_atop_reverse,
+    [PictOpXor] = xa_op_xor,
+    [PictOpAdd] = xa_op_add
+};
+
+static const unsigned int vmwgfx_op_map_size =
+    sizeof(vmwgfx_op_map) / sizeof(enum xa_composite_op);
+
+static Bool
+vmwgfx_matrix_from_pict_transform(PictTransform *trans, float *matrix)
+{
+   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 enum xa_composite_wrap
+vmwgfx_xa_setup_wrap(Bool pict_has_repeat, int pict_repeat)
+{
+    enum xa_composite_wrap wrap = xa_wrap_clamp_to_border;
+
+    if (!pict_has_repeat)
+       return wrap;
+
+    switch(pict_repeat) {
+    case RepeatNormal:
+       wrap = xa_wrap_repeat;
+       break;
+    case RepeatReflect:
+       wrap = xa_wrap_mirror_repeat;
+       break;
+    case RepeatPad:
+       wrap = xa_wrap_clamp_to_edge;
+       break;
+    default:
+       break;
+    }
+    return wrap;
+}
+
+static Bool
+vmwgfx_render_filter_to_xa(int xrender_filter,
+                          enum xa_composite_filter *out_filter)
+{
+   switch (xrender_filter) {
+   case PictFilterConvolution:
+   case PictFilterNearest:
+   case PictFilterFast:
+       *out_filter = xa_filter_nearest;
+      break;
+   case PictFilterBest:
+   case PictFilterGood:
+   case PictFilterBilinear:
+       *out_filter = xa_filter_linear;
+      break;
+   default:
+       *out_filter = xa_filter_nearest;
+       return FALSE;
+   }
+   return TRUE;
+}
+
+static Bool
+vmwgfx_xa_setup_pict(PicturePtr pict,
+                    struct xa_picture *xa_pict,
+                    union xa_source_pict *src_pict)
+{
+    if (!pict)
+       return FALSE;
+
+    memset(xa_pict, 0, sizeof(*xa_pict));
+
+    xa_pict->pict_format = vmwgfx_xa_format(pict->format);
+    if (xa_pict->pict_format == xa_format_unknown)
+       return FALSE;
+
+    /*
+     * Saa doesn't let drivers accelerate alpha maps.
+     */
+    xa_pict->alpha_map = NULL;
+    xa_pict->component_alpha = pict->componentAlpha;
+
+    xa_pict->has_transform =
+       vmwgfx_matrix_from_pict_transform(pict->transform,
+                                         xa_pict->transform);
+
+    xa_pict->wrap = vmwgfx_xa_setup_wrap(pict->repeat,
+                                        pict->repeatType);
+
+    (void) vmwgfx_render_filter_to_xa(pict->filter, &xa_pict->filter);
+
+    if (pict->pSourcePict) {
+       if (pict->pSourcePict->type != SourcePictTypeSolidFill)
+           return FALSE;
+
+       src_pict->type = xa_src_pict_solid_fill;
+       src_pict->solid_fill.color = pict->pSourcePict->solidFill.color;
+       xa_pict->src_pict = src_pict;
+    }
+
+    return TRUE;
+}
+
+struct xa_composite *
+vmwgfx_xa_setup_comp(struct vmwgfx_composite *vcomp,
+                    int op,
+                    PicturePtr src_pict,
+                    PicturePtr mask_pict,
+                    PicturePtr dst_pict)
+{
+    struct xa_composite *comp = vcomp->comp;
+
+    if (op >= vmwgfx_op_map_size)
+       return NULL;
+
+    comp->op = vmwgfx_op_map[op];
+    if (comp->op == xa_op_clear && op != PictOpClear)
+       return NULL;
+
+    if (!vmwgfx_xa_setup_pict(dst_pict, vcomp->dst_pict,
+                             vcomp->dst_spict))
+       return NULL;
+    if (!vmwgfx_xa_setup_pict(src_pict, vcomp->src_pict,
+                             vcomp->src_spict))
+       return NULL;
+    if (mask_pict && !vmwgfx_xa_setup_pict(mask_pict,
+                                          vcomp->mask_pict,
+                                          vcomp->mask_spict))
+       return NULL;
+
+    comp->dst = vcomp->dst_pict;
+    comp->src = vcomp->src_pict;
+    comp->mask = (mask_pict) ? vcomp->mask_pict : NULL;
+
+    return comp;
+}
+
+Bool
+vmwgfx_xa_update_comp(struct xa_composite *comp,
+                     PixmapPtr src_pix,
+                     PixmapPtr mask_pix,
+                     PixmapPtr dst_pix)
+{
+    comp->dst->srf = vmwgfx_saa_pixmap(dst_pix)->hw;
+    if (src_pix)
+       comp->src->srf = vmwgfx_saa_pixmap(src_pix)->hw;
+    if (mask_pix && comp->mask)
+       comp->mask->srf = vmwgfx_saa_pixmap(mask_pix)->hw;
+    return TRUE;
+}
+
+
+void
+vmwgfx_free_composite(struct vmwgfx_composite *vcomp)
+{
+    if (!vcomp)
+       return;
+
+    if (vcomp->src_spict)
+       free(vcomp->src_spict);
+    if (vcomp->mask_spict)
+       free(vcomp->mask_spict);
+    if (vcomp->dst_spict)
+       free(vcomp->dst_spict);
+    if (vcomp->src_pict)
+       free(vcomp->src_pict);
+    if (vcomp->mask_pict)
+       free(vcomp->mask_pict);
+    if (vcomp->dst_pict)
+       free(vcomp->dst_pict);
+    if (vcomp->comp)
+       free(vcomp->comp);
+    free(vcomp);
+}
+
+struct vmwgfx_composite *
+vmwgfx_alloc_composite(void)
+{
+    const struct xa_composite_allocation *a = xa_composite_allocation();
+    struct vmwgfx_composite *vcomp = calloc(1, sizeof(*vcomp));
+
+    if (!vcomp)
+       return NULL;
+
+    vcomp->src_spict = calloc(1, a->xa_source_pict_size);
+    vcomp->mask_spict = calloc(1, a->xa_source_pict_size);
+    vcomp->dst_spict = calloc(1, a->xa_source_pict_size);
+    vcomp->src_pict = calloc(1, a->xa_picture_size);
+    vcomp->mask_pict = calloc(1, a->xa_picture_size);
+    vcomp->dst_pict = calloc(1, a->xa_picture_size);
+    vcomp->comp = calloc(1, a->xa_composite_size);
+
+    if (!vcomp->src_spict || !vcomp->mask_spict || !vcomp->dst_spict ||
+       !vcomp->src_pict || !vcomp->mask_pict || !vcomp->dst_pict ||
+       !vcomp->comp) {
+       vmwgfx_free_composite(vcomp);
+       return NULL;
+    }
+
+    return vcomp;
+}