summaryrefslogtreecommitdiff
path: root/vmwgfx/vmwgfx_xa_surface.c
diff options
context:
space:
mode:
Diffstat (limited to 'vmwgfx/vmwgfx_xa_surface.c')
-rw-r--r--vmwgfx/vmwgfx_xa_surface.c368
1 files changed, 368 insertions, 0 deletions
diff --git a/vmwgfx/vmwgfx_xa_surface.c b/vmwgfx/vmwgfx_xa_surface.c
new file mode 100644
index 0000000..2a18762
--- /dev/null
+++ b/vmwgfx/vmwgfx_xa_surface.c
@@ -0,0 +1,368 @@
+/*
+ * Copyright 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>
+ */
+#ifdef _HAVE_CONFIG_H_
+#include "config.h"
+#endif
+
+#include <xorg-server.h>
+#include "vmwgfx_saa_priv.h"
+
+
+static const enum xa_surface_type vmwgfx_stype_map[] = {
+ [PICT_TYPE_OTHER] = xa_type_other,
+ [PICT_TYPE_A] = xa_type_a,
+ [PICT_TYPE_ARGB] = xa_type_argb,
+ [PICT_TYPE_ABGR] = xa_type_abgr,
+ [PICT_TYPE_BGRA] = xa_type_bgra
+};
+
+static const unsigned int vmwgfx_stype_map_size =
+ sizeof(vmwgfx_stype_map) / sizeof(enum xa_surface_type);
+
+
+/*
+ * Create an xa format from a PICT format.
+ */
+enum xa_formats
+vmwgfx_xa_format(enum _PictFormatShort format)
+{
+ uint32_t ptype = PICT_FORMAT_TYPE(format);
+
+ if (ptype >= vmwgfx_stype_map_size ||
+ vmwgfx_stype_map[ptype] == 0 ||
+ vmwgfx_stype_map[ptype] == xa_type_other)
+ return xa_format_unknown;
+
+ return xa_format(PICT_FORMAT_BPP(format),
+ vmwgfx_stype_map[ptype],
+ PICT_FORMAT_A(format),
+ PICT_FORMAT_R(format),
+ PICT_FORMAT_G(format),
+ PICT_FORMAT_B(format));
+}
+
+/*
+ * Choose formats and flags for a dri2 surface.
+ */
+static Bool
+vmwgfx_hw_dri2_stage(PixmapPtr pixmap, unsigned int depth)
+{
+ struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
+ enum xa_formats format;
+
+ if (depth == 0)
+ depth = pixmap->drawable.depth;
+
+ switch(depth) {
+ case 32:
+ format = xa_format_a8r8g8b8;
+ break;
+ case 24:
+ format = xa_format_x8r8g8b8;
+ break;
+ case 16:
+ format = xa_format_r5g6b5;
+ break;
+ case 15:
+ format = xa_format_x1r5g5b5;
+ break;
+ default:
+ return FALSE;
+ }
+
+ vpix->staging_format = format;
+ vpix->staging_remove_flags = 0;
+ vpix->staging_add_flags = XA_FLAG_RENDER_TARGET | XA_FLAG_SHARED;
+
+ return TRUE;
+}
+
+/*
+ * Is composite old format compatible? Only difference is that old format
+ * has more alpha bits?
+ */
+static inline Bool
+vmwgfx_old_format_compatible(enum xa_formats format,
+ enum xa_formats old_format)
+{
+ return (format == old_format ||
+ (xa_format_type(format) == xa_format_type(old_format) &&
+ xa_format_a(format) <= xa_format_a(old_format) &&
+ xa_format_r(format) == xa_format_r(old_format) &&
+ xa_format_g(format) == xa_format_g(old_format) &&
+ xa_format_b(format) == xa_format_b(old_format)));
+}
+
+
+/*
+ * Choose format and flags for a composite dst surface.
+ */
+Bool
+vmwgfx_hw_composite_dst_stage(PixmapPtr pixmap,
+ enum _PictFormatShort pict_format)
+{
+ struct vmwgfx_saa *vsaa =
+ to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen));
+ struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
+ enum xa_formats format = vmwgfx_xa_format(pict_format);
+
+ /*
+ * Check if we can reuse old hardware format.
+ */
+ if (vpix->hw) {
+ enum xa_formats old_format = xa_surface_format(vpix->hw);
+
+ if (vmwgfx_old_format_compatible(format, old_format))
+ format = old_format;
+ }
+
+ if (xa_format_check_supported(vsaa->xat, format,
+ vpix->xa_flags | XA_FLAG_RENDER_TARGET) !=
+ XA_ERR_NONE) {
+ return FALSE;
+ }
+
+ vpix->staging_format = format;
+ vpix->staging_remove_flags = 0;
+ vpix->staging_add_flags = XA_FLAG_RENDER_TARGET;
+
+ return TRUE;
+}
+
+/*
+ * Choose format and flags for a composite src surface.
+ */
+Bool
+vmwgfx_hw_composite_src_stage(PixmapPtr pixmap,
+ enum _PictFormatShort pict_format)
+{
+ struct vmwgfx_saa *vsaa =
+ to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen));
+ struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
+ enum xa_formats format = vmwgfx_xa_format(pict_format);
+ enum xa_formats swizzle_format = xa_format_unknown;
+ enum xa_surface_type ftype;
+
+ if (format == xa_format_unknown)
+ return FALSE;
+
+ ftype = xa_format_type(format);
+ if (ftype == xa_type_abgr) {
+
+ swizzle_format = xa_format(xa_format_bpp(format),
+ xa_type_argb,
+ xa_format_a(format),
+ xa_format_r(format),
+ xa_format_g(format),
+ xa_format_b(format));
+ }
+
+ /*
+ * Check if we can reuse old format.
+ */
+
+ if (vpix->hw) {
+ enum xa_formats old_format = xa_surface_format(vpix->hw);
+
+ if (vmwgfx_old_format_compatible(format, old_format) ||
+ (swizzle_format != xa_format_unknown &&
+ vmwgfx_old_format_compatible(swizzle_format, old_format))) {
+ format = old_format;
+ goto have_format;
+ }
+ }
+
+ if (swizzle_format != xa_format_unknown &&
+ xa_format_check_supported(vsaa->xat, swizzle_format, vpix->xa_flags) ==
+ XA_ERR_NONE) {
+ format = swizzle_format;
+ goto have_format;
+ }
+
+ if (xa_format_check_supported(vsaa->xat, format, vpix->xa_flags) ==
+ XA_ERR_NONE) {
+ goto have_format;
+ }
+
+ return FALSE;
+ have_format:
+ vpix->staging_format = format;
+ vpix->staging_remove_flags = 0;
+ vpix->staging_add_flags = 0;
+
+ return TRUE;
+}
+
+/*
+ * Choose accel format given depth.
+ */
+static enum xa_formats
+vmwgfx_choose_accel_format(unsigned int depth)
+{
+ switch(depth) {
+ case 32:
+ return xa_format_a8r8g8b8;
+ case 24:
+ return xa_format_x8r8g8b8;
+ case 16:
+ return xa_format_r5g6b5;
+ case 15:
+ return xa_format_x1r5g5b5;
+ case 8:
+ return xa_format_a8;
+ default:
+ break;
+ }
+ return xa_format_unknown;
+}
+
+
+/*
+ * Determine xa format and flags for an ordinary accel surface.
+ */
+Bool
+vmwgfx_hw_accel_stage(PixmapPtr pixmap, unsigned int depth,
+ uint32_t add_flags, uint32_t remove_flags)
+{
+ struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
+ enum xa_formats format = xa_format_unknown;
+
+ if (depth == 0)
+ depth = pixmap->drawable.depth;
+
+ if (vpix->hw) {
+ enum xa_formats old_format = xa_surface_format(vpix->hw);
+ enum xa_surface_type ftype = xa_format_type(old_format);
+
+ if (ftype != xa_type_argb &&
+ ftype != xa_type_a) {
+ LogMessage(X_ERROR,
+ "Acceleration fallback due to strange hw format.\n");
+ return FALSE;
+ }
+
+ if (xa_format_depth(old_format) == depth ||
+ (xa_format_depth(old_format) == 32 &&
+ depth == 24))
+ format = old_format;
+ }
+
+ if (format == xa_format_unknown)
+ format = vmwgfx_choose_accel_format(depth);
+
+ if (format == xa_format_unknown)
+ return FALSE;
+
+ vpix->staging_add_flags = add_flags;
+ vpix->staging_remove_flags = remove_flags;
+ vpix->staging_format = format;
+
+ return TRUE;
+}
+
+/*
+ * Create a surface with a format and flags determined by one of
+ * the staging functions.
+ */
+Bool
+vmwgfx_hw_commit(PixmapPtr pixmap)
+{
+ struct vmwgfx_saa *vsaa =
+ to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen));
+ struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
+ struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
+ enum xa_formats format = vpix->staging_format;
+
+ if (vpix->hw) {
+ enum xa_formats old_format = xa_surface_format(vpix->hw);
+
+ if (vpix->staging_format != old_format) {
+ if (xa_format_type(format) != xa_format_type(old_format) ||
+ xa_format_r(format) != xa_format_r(old_format) ||
+ xa_format_g(format) != xa_format_g(old_format) ||
+ xa_format_b(format) != xa_format_b(old_format)) {
+
+ LogMessage(X_INFO, "Killing old hw surface.\n");
+
+ if (!vmwgfx_hw_kill(vsaa, spix))
+ return FALSE;
+ }
+ }
+ }
+
+ if (vpix->hw) {
+ uint32_t new_flags;
+
+ new_flags = (vpix->xa_flags & ~vpix->staging_remove_flags) |
+ vpix->staging_add_flags;
+
+ if (vpix->staging_format != xa_surface_format(vpix->hw))
+ LogMessage(X_INFO, "Changing hardware format.\n");
+
+ if (xa_surface_redefine(vpix->hw,
+ pixmap->drawable.width,
+ pixmap->drawable.height,
+ 0,
+ xa_type_other,
+ vpix->staging_format,
+ new_flags, 1) != XA_ERR_NONE)
+ return FALSE;
+ vpix->xa_flags = new_flags;
+ } else if (!vmwgfx_create_hw(vsaa, pixmap))
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * Create an accel surface if there is none, and make sure the region
+ * given by @region is valid. If @region is NULL, the whole surface
+ * will be valid. This is a utility convenience function only.
+ */
+Bool
+vmwgfx_hw_accel_validate(PixmapPtr pixmap, unsigned int depth,
+ uint32_t add_flags, uint32_t remove_flags,
+ RegionPtr region)
+{
+ return (vmwgfx_hw_accel_stage(pixmap, depth, add_flags, remove_flags) &&
+ vmwgfx_hw_commit(pixmap) &&
+ vmwgfx_hw_validate(pixmap, region));
+}
+
+
+/*
+ * Create a dri2 surface if there is none,
+ * and make sure the whole surfade is valid.
+ * This is a utility convenience function only.
+ */
+Bool
+vmwgfx_hw_dri2_validate(PixmapPtr pixmap, unsigned int depth)
+{
+ return (vmwgfx_hw_dri2_stage(pixmap, depth) &&
+ vmwgfx_hw_commit(pixmap) &&
+ vmwgfx_hw_validate(pixmap, NULL));
+}