diff options
Diffstat (limited to 'driver/xf86-video-vmware/vmwgfx/vmwgfx_xa_surface.c')
-rw-r--r-- | driver/xf86-video-vmware/vmwgfx/vmwgfx_xa_surface.c | 368 |
1 files changed, 368 insertions, 0 deletions
diff --git a/driver/xf86-video-vmware/vmwgfx/vmwgfx_xa_surface.c b/driver/xf86-video-vmware/vmwgfx/vmwgfx_xa_surface.c new file mode 100644 index 000000000..2a18762f5 --- /dev/null +++ b/driver/xf86-video-vmware/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)); +} |