vmwgfx_xa_surface.c revision 22f7e8e5
13bfa90b6Smrg/*
23bfa90b6Smrg * Copyright 2011 VMWare, Inc.
33bfa90b6Smrg * All Rights Reserved.
43bfa90b6Smrg *
53bfa90b6Smrg * Permission is hereby granted, free of charge, to any person obtaining a
63bfa90b6Smrg * copy of this software and associated documentation files (the
73bfa90b6Smrg * "Software"), to deal in the Software without restriction, including
83bfa90b6Smrg * without limitation the rights to use, copy, modify, merge, publish,
93bfa90b6Smrg * distribute, sub license, and/or sell copies of the Software, and to
103bfa90b6Smrg * permit persons to whom the Software is furnished to do so, subject to
113bfa90b6Smrg * the following conditions:
123bfa90b6Smrg *
133bfa90b6Smrg * The above copyright notice and this permission notice (including the
143bfa90b6Smrg * next paragraph) shall be included in all copies or substantial portions
153bfa90b6Smrg * of the Software.
163bfa90b6Smrg *
173bfa90b6Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
183bfa90b6Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
193bfa90b6Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
203bfa90b6Smrg * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
213bfa90b6Smrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
223bfa90b6Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
233bfa90b6Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
243bfa90b6Smrg *
253bfa90b6Smrg * Author: Thomas Hellstrom <thellstrom@vmware.com>
263bfa90b6Smrg */
273bfa90b6Smrg#ifdef _HAVE_CONFIG_H_
283bfa90b6Smrg#include "config.h"
293bfa90b6Smrg#endif
303bfa90b6Smrg
313bfa90b6Smrg#include <xorg-server.h>
323bfa90b6Smrg#include "vmwgfx_saa_priv.h"
333bfa90b6Smrg
343bfa90b6Smrg
353bfa90b6Smrgstatic const enum xa_surface_type vmwgfx_stype_map[] = {
363bfa90b6Smrg  [PICT_TYPE_OTHER] = xa_type_other,
373bfa90b6Smrg  [PICT_TYPE_A] = xa_type_a,
383bfa90b6Smrg  [PICT_TYPE_ARGB] = xa_type_argb,
393bfa90b6Smrg  [PICT_TYPE_ABGR] = xa_type_abgr,
403bfa90b6Smrg  [PICT_TYPE_BGRA] = xa_type_bgra
413bfa90b6Smrg};
423bfa90b6Smrg
433bfa90b6Smrgstatic const unsigned int vmwgfx_stype_map_size =
443bfa90b6Smrg    sizeof(vmwgfx_stype_map) / sizeof(enum xa_surface_type);
453bfa90b6Smrg
463bfa90b6Smrg
473bfa90b6Smrg/*
483bfa90b6Smrg * Create an xa format from a PICT format.
493bfa90b6Smrg */
503bfa90b6Smrgenum xa_formats
513bfa90b6Smrgvmwgfx_xa_format(enum _PictFormatShort format)
523bfa90b6Smrg{
533bfa90b6Smrg    uint32_t ptype = PICT_FORMAT_TYPE(format);
543bfa90b6Smrg
553bfa90b6Smrg    if (ptype >= vmwgfx_stype_map_size ||
563bfa90b6Smrg	vmwgfx_stype_map[ptype] == 0 ||
573bfa90b6Smrg	vmwgfx_stype_map[ptype] == xa_type_other)
583bfa90b6Smrg	return xa_format_unknown;
593bfa90b6Smrg
603bfa90b6Smrg    return xa_format(PICT_FORMAT_BPP(format),
613bfa90b6Smrg		     vmwgfx_stype_map[ptype],
623bfa90b6Smrg		     PICT_FORMAT_A(format),
633bfa90b6Smrg		     PICT_FORMAT_R(format),
643bfa90b6Smrg		     PICT_FORMAT_G(format),
653bfa90b6Smrg		     PICT_FORMAT_B(format));
663bfa90b6Smrg}
673bfa90b6Smrg
683bfa90b6Smrg/*
693bfa90b6Smrg * Choose formats and flags for a dri2 surface.
703bfa90b6Smrg */
713bfa90b6Smrgstatic Bool
723bfa90b6Smrgvmwgfx_hw_dri2_stage(PixmapPtr pixmap, unsigned int depth)
733bfa90b6Smrg{
743bfa90b6Smrg    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
753bfa90b6Smrg    enum xa_formats format;
763bfa90b6Smrg
773bfa90b6Smrg    if (depth == 0)
783bfa90b6Smrg	depth = pixmap->drawable.depth;
793bfa90b6Smrg
803bfa90b6Smrg    switch(depth) {
813bfa90b6Smrg    case 32:
823bfa90b6Smrg	format = xa_format_a8r8g8b8;
833bfa90b6Smrg	break;
843bfa90b6Smrg    case 24:
853bfa90b6Smrg        format = xa_format_x8r8g8b8;
863bfa90b6Smrg	break;
873bfa90b6Smrg    case 16:
883bfa90b6Smrg	format = xa_format_r5g6b5;
893bfa90b6Smrg	break;
903bfa90b6Smrg    case 15:
913bfa90b6Smrg	format = xa_format_x1r5g5b5;
923bfa90b6Smrg	break;
933bfa90b6Smrg    default:
943bfa90b6Smrg	return FALSE;
953bfa90b6Smrg    }
963bfa90b6Smrg
973bfa90b6Smrg    vpix->staging_format = format;
983bfa90b6Smrg    vpix->staging_remove_flags = 0;
993bfa90b6Smrg    vpix->staging_add_flags = XA_FLAG_RENDER_TARGET | XA_FLAG_SHARED;
1003bfa90b6Smrg
1013bfa90b6Smrg    return TRUE;
1023bfa90b6Smrg}
1033bfa90b6Smrg
1043bfa90b6Smrg/*
1053bfa90b6Smrg * Is composite old format compatible? Only difference is that old format
1063bfa90b6Smrg * has more alpha bits?
1073bfa90b6Smrg */
1083bfa90b6Smrgstatic inline Bool
1093bfa90b6Smrgvmwgfx_old_format_compatible(enum xa_formats format,
1103bfa90b6Smrg			     enum xa_formats old_format)
1113bfa90b6Smrg{
1123bfa90b6Smrg    return (format == old_format ||
1133bfa90b6Smrg	    (xa_format_type(format) == xa_format_type(old_format) &&
1143bfa90b6Smrg	     xa_format_a(format) <= xa_format_a(old_format) &&
1153bfa90b6Smrg	     xa_format_r(format) == xa_format_r(old_format) &&
1163bfa90b6Smrg	     xa_format_g(format) == xa_format_g(old_format) &&
1173bfa90b6Smrg	     xa_format_b(format) == xa_format_b(old_format)));
1183bfa90b6Smrg}
1193bfa90b6Smrg
1203bfa90b6Smrg
1213bfa90b6Smrg/*
1223bfa90b6Smrg * Choose format and flags for a composite dst surface.
1233bfa90b6Smrg */
1243bfa90b6SmrgBool
1253bfa90b6Smrgvmwgfx_hw_composite_dst_stage(PixmapPtr pixmap,
1263bfa90b6Smrg			      enum _PictFormatShort pict_format)
1273bfa90b6Smrg{
1283bfa90b6Smrg    struct vmwgfx_saa *vsaa =
1293bfa90b6Smrg	to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen));
1303bfa90b6Smrg    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
1313bfa90b6Smrg    enum xa_formats format = vmwgfx_xa_format(pict_format);
1323bfa90b6Smrg
1333bfa90b6Smrg    /*
1343bfa90b6Smrg     * Check if we can reuse old hardware format.
1353bfa90b6Smrg     */
1363bfa90b6Smrg    if (vpix->hw) {
1373bfa90b6Smrg	enum xa_formats old_format = xa_surface_format(vpix->hw);
1383bfa90b6Smrg
1393bfa90b6Smrg	if (vmwgfx_old_format_compatible(format, old_format))
1403bfa90b6Smrg	    format = old_format;
1413bfa90b6Smrg    }
1423bfa90b6Smrg
1433bfa90b6Smrg    if (xa_format_check_supported(vsaa->xat, format,
1443bfa90b6Smrg				  vpix->xa_flags | XA_FLAG_RENDER_TARGET) !=
1453bfa90b6Smrg	XA_ERR_NONE) {
1463bfa90b6Smrg	return FALSE;
1473bfa90b6Smrg    }
1483bfa90b6Smrg
1493bfa90b6Smrg    vpix->staging_format = format;
1503bfa90b6Smrg    vpix->staging_remove_flags = 0;
1513bfa90b6Smrg    vpix->staging_add_flags = XA_FLAG_RENDER_TARGET | XA_FLAG_SHARED;
1523bfa90b6Smrg
1533bfa90b6Smrg    return TRUE;
1543bfa90b6Smrg}
1553bfa90b6Smrg
1563bfa90b6Smrg/*
1573bfa90b6Smrg * Choose format and flags for a composite src surface.
1583bfa90b6Smrg */
1593bfa90b6SmrgBool
1603bfa90b6Smrgvmwgfx_hw_composite_src_stage(PixmapPtr pixmap,
1613bfa90b6Smrg			      enum _PictFormatShort pict_format)
1623bfa90b6Smrg{
1633bfa90b6Smrg    struct vmwgfx_saa *vsaa =
1643bfa90b6Smrg	to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen));
1653bfa90b6Smrg    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
1663bfa90b6Smrg    enum xa_formats format = vmwgfx_xa_format(pict_format);
1673bfa90b6Smrg    enum xa_formats swizzle_format = xa_format_unknown;
1683bfa90b6Smrg    enum xa_surface_type ftype;
1693bfa90b6Smrg
1703bfa90b6Smrg    if (format == xa_format_unknown)
1713bfa90b6Smrg	return FALSE;
1723bfa90b6Smrg
1733bfa90b6Smrg    ftype = xa_format_type(format);
1743bfa90b6Smrg    if (ftype == xa_type_abgr) {
1753bfa90b6Smrg
1763bfa90b6Smrg	swizzle_format = xa_format(xa_format_bpp(format),
1773bfa90b6Smrg				   xa_type_argb,
1783bfa90b6Smrg				   xa_format_a(format),
1793bfa90b6Smrg				   xa_format_r(format),
1803bfa90b6Smrg				   xa_format_g(format),
1813bfa90b6Smrg				   xa_format_b(format));
1823bfa90b6Smrg    }
1833bfa90b6Smrg
1843bfa90b6Smrg    /*
1853bfa90b6Smrg     * Check if we can reuse old format.
1863bfa90b6Smrg     */
1873bfa90b6Smrg
1883bfa90b6Smrg    if (vpix->hw) {
1893bfa90b6Smrg	enum xa_formats old_format = xa_surface_format(vpix->hw);
1903bfa90b6Smrg
1913bfa90b6Smrg	if (vmwgfx_old_format_compatible(format, old_format) ||
1923bfa90b6Smrg	    (swizzle_format != xa_format_unknown &&
1933bfa90b6Smrg	     vmwgfx_old_format_compatible(swizzle_format, old_format))) {
1943bfa90b6Smrg	    format = old_format;
1953bfa90b6Smrg	    goto have_format;
1963bfa90b6Smrg	}
1973bfa90b6Smrg    }
1983bfa90b6Smrg
1993bfa90b6Smrg    if (swizzle_format != xa_format_unknown &&
2003bfa90b6Smrg	xa_format_check_supported(vsaa->xat, swizzle_format, vpix->xa_flags) ==
2013bfa90b6Smrg	XA_ERR_NONE) {
2023bfa90b6Smrg	format = swizzle_format;
2033bfa90b6Smrg	goto have_format;
2043bfa90b6Smrg    }
2053bfa90b6Smrg
2063bfa90b6Smrg    if (xa_format_check_supported(vsaa->xat, format, vpix->xa_flags) ==
2073bfa90b6Smrg	XA_ERR_NONE) {
2083bfa90b6Smrg	goto have_format;
2093bfa90b6Smrg    }
2103bfa90b6Smrg
2113bfa90b6Smrg    return FALSE;
2123bfa90b6Smrg  have_format:
2133bfa90b6Smrg    vpix->staging_format = format;
2143bfa90b6Smrg    vpix->staging_remove_flags = 0;
2153bfa90b6Smrg    vpix->staging_add_flags = 0;
2163bfa90b6Smrg
2173bfa90b6Smrg    return TRUE;
2183bfa90b6Smrg}
2193bfa90b6Smrg
2203bfa90b6Smrg/*
2213bfa90b6Smrg * Choose accel format given depth.
2223bfa90b6Smrg */
2233bfa90b6Smrgstatic enum xa_formats
2243bfa90b6Smrgvmwgfx_choose_accel_format(unsigned int depth)
2253bfa90b6Smrg{
2263bfa90b6Smrg    switch(depth) {
2273bfa90b6Smrg    case 32:
2283bfa90b6Smrg	return xa_format_a8r8g8b8;
2293bfa90b6Smrg    case 24:
2303bfa90b6Smrg	return xa_format_x8r8g8b8;
2313bfa90b6Smrg    case 16:
2323bfa90b6Smrg	return xa_format_r5g6b5;
2333bfa90b6Smrg    case 15:
2343bfa90b6Smrg	return xa_format_x1r5g5b5;
2353bfa90b6Smrg    case 8:
2363bfa90b6Smrg	return xa_format_a8;
2373bfa90b6Smrg    default:
2383bfa90b6Smrg	break;
2393bfa90b6Smrg    }
2403bfa90b6Smrg    return xa_format_unknown;
2413bfa90b6Smrg}
2423bfa90b6Smrg
2433bfa90b6Smrg
2443bfa90b6Smrg/*
2453bfa90b6Smrg * Determine xa format and flags for an ordinary accel surface.
2463bfa90b6Smrg */
2473bfa90b6SmrgBool
2483bfa90b6Smrgvmwgfx_hw_accel_stage(PixmapPtr pixmap, unsigned int depth,
2493bfa90b6Smrg		      uint32_t add_flags, uint32_t remove_flags)
2503bfa90b6Smrg{
2513bfa90b6Smrg    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
2523bfa90b6Smrg    enum xa_formats format = xa_format_unknown;
2533bfa90b6Smrg
2543bfa90b6Smrg    if (depth == 0)
2553bfa90b6Smrg	depth = pixmap->drawable.depth;
2563bfa90b6Smrg
2573bfa90b6Smrg    if (vpix->hw) {
2583bfa90b6Smrg	enum xa_formats old_format = xa_surface_format(vpix->hw);
2593bfa90b6Smrg	enum xa_surface_type ftype = xa_format_type(old_format);
2603bfa90b6Smrg
2613bfa90b6Smrg	if (ftype != xa_type_argb &&
2623bfa90b6Smrg	    ftype != xa_type_a) {
2633bfa90b6Smrg	    LogMessage(X_ERROR,
2643bfa90b6Smrg		       "Acceleration fallback due to strange hw format.\n");
2653bfa90b6Smrg	    return FALSE;
2663bfa90b6Smrg	}
2673bfa90b6Smrg
2683bfa90b6Smrg	if (xa_format_depth(old_format) == depth ||
2693bfa90b6Smrg	    (xa_format_depth(old_format) == 32 &&
2703bfa90b6Smrg	     depth == 24))
2713bfa90b6Smrg	    format = old_format;
2723bfa90b6Smrg    }
2733bfa90b6Smrg
2743bfa90b6Smrg    if (format == xa_format_unknown)
2753bfa90b6Smrg	format = vmwgfx_choose_accel_format(depth);
2763bfa90b6Smrg
2773bfa90b6Smrg    if (format == xa_format_unknown)
2783bfa90b6Smrg	return FALSE;
2793bfa90b6Smrg
2803bfa90b6Smrg    vpix->staging_add_flags = add_flags;
2813bfa90b6Smrg    vpix->staging_remove_flags = remove_flags;
2823bfa90b6Smrg    vpix->staging_format = format;
2833bfa90b6Smrg
2843bfa90b6Smrg    return TRUE;
2853bfa90b6Smrg}
2863bfa90b6Smrg
2873bfa90b6Smrg/*
2883bfa90b6Smrg * Create a surface with a format and flags determined by one of
2893bfa90b6Smrg * the staging functions.
2903bfa90b6Smrg */
2913bfa90b6SmrgBool
2923bfa90b6Smrgvmwgfx_hw_commit(PixmapPtr pixmap)
2933bfa90b6Smrg{
2943bfa90b6Smrg    struct vmwgfx_saa *vsaa =
2953bfa90b6Smrg	to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen));
2963bfa90b6Smrg    struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
2973bfa90b6Smrg    struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
2983bfa90b6Smrg    enum xa_formats format = vpix->staging_format;
2993bfa90b6Smrg
3003bfa90b6Smrg    if (vpix->hw) {
3013bfa90b6Smrg	enum xa_formats old_format = xa_surface_format(vpix->hw);
3023bfa90b6Smrg
3033bfa90b6Smrg	if (vpix->staging_format != old_format) {
3043bfa90b6Smrg	    if (xa_format_type(format) != xa_format_type(old_format) ||
3053bfa90b6Smrg		xa_format_r(format) != xa_format_r(old_format) ||
3063bfa90b6Smrg		xa_format_g(format) != xa_format_g(old_format) ||
3073bfa90b6Smrg		xa_format_b(format) != xa_format_b(old_format)) {
3083bfa90b6Smrg
3093bfa90b6Smrg		LogMessage(X_INFO, "Killing old hw surface.\n");
3103bfa90b6Smrg
3113bfa90b6Smrg		if (!vmwgfx_hw_kill(vsaa, spix))
3123bfa90b6Smrg		    return FALSE;
3133bfa90b6Smrg	    }
3143bfa90b6Smrg	}
3153bfa90b6Smrg    }
3163bfa90b6Smrg
3173bfa90b6Smrg    if (vpix->hw) {
3183bfa90b6Smrg	uint32_t new_flags;
3193bfa90b6Smrg
3203bfa90b6Smrg	new_flags = (vpix->xa_flags & ~vpix->staging_remove_flags) |
32122f7e8e5Smrg	    vpix->staging_add_flags | XA_FLAG_SHARED;
3223bfa90b6Smrg
3233bfa90b6Smrg	if (vpix->staging_format != xa_surface_format(vpix->hw))
3243bfa90b6Smrg	    LogMessage(X_INFO, "Changing hardware format.\n");
3253bfa90b6Smrg
3263bfa90b6Smrg	if (xa_surface_redefine(vpix->hw,
3273bfa90b6Smrg				pixmap->drawable.width,
3283bfa90b6Smrg				pixmap->drawable.height,
3293bfa90b6Smrg				0,
3303bfa90b6Smrg				xa_type_other,
3313bfa90b6Smrg				vpix->staging_format,
3323bfa90b6Smrg				new_flags, 1) != XA_ERR_NONE)
3333bfa90b6Smrg	    return FALSE;
3343bfa90b6Smrg	vpix->xa_flags = new_flags;
3353bfa90b6Smrg    } else if (!vmwgfx_create_hw(vsaa, pixmap))
3363bfa90b6Smrg	return FALSE;
3373bfa90b6Smrg
3383bfa90b6Smrg    return TRUE;
3393bfa90b6Smrg}
3403bfa90b6Smrg
3413bfa90b6Smrg/*
3423bfa90b6Smrg * Create an accel surface if there is none, and make sure the region
3433bfa90b6Smrg * given by @region is valid. If @region is NULL, the whole surface
3443bfa90b6Smrg * will be valid. This is a utility convenience function only.
3453bfa90b6Smrg */
3463bfa90b6SmrgBool
3473bfa90b6Smrgvmwgfx_hw_accel_validate(PixmapPtr pixmap, unsigned int depth,
3483bfa90b6Smrg			 uint32_t add_flags, uint32_t remove_flags,
3493bfa90b6Smrg			 RegionPtr region)
3503bfa90b6Smrg{
3513bfa90b6Smrg    return (vmwgfx_hw_accel_stage(pixmap, depth, add_flags, remove_flags) &&
3523bfa90b6Smrg	    vmwgfx_hw_commit(pixmap) &&
3533bfa90b6Smrg	    vmwgfx_hw_validate(pixmap, region));
3543bfa90b6Smrg}
3553bfa90b6Smrg
3563bfa90b6Smrg
3573bfa90b6Smrg/*
3583bfa90b6Smrg * Create a dri2 surface if there is none,
3593bfa90b6Smrg * and make sure the whole surfade is valid.
3603bfa90b6Smrg * This is a utility convenience function only.
3613bfa90b6Smrg */
3623bfa90b6SmrgBool
3633bfa90b6Smrgvmwgfx_hw_dri2_validate(PixmapPtr pixmap, unsigned int depth)
3643bfa90b6Smrg{
36522f7e8e5Smrg    struct vmwgfx_saa *vsaa =
36622f7e8e5Smrg	to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen));
36722f7e8e5Smrg
36822f7e8e5Smrg    if (!vsaa->is_master)
36922f7e8e5Smrg	    return FALSE;
37022f7e8e5Smrg
3713bfa90b6Smrg    return (vmwgfx_hw_dri2_stage(pixmap, depth) &&
3723bfa90b6Smrg	    vmwgfx_hw_commit(pixmap) &&
3733bfa90b6Smrg	    vmwgfx_hw_validate(pixmap, NULL));
3743bfa90b6Smrg}
375