xenocara/driver/xf86-video-vmware/vmwgfx/vmwgfx_xa_surface.c
2015-01-25 18:57:12 +00:00

422 lines
11 KiB
C

/*
* 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);
/**
* vmwgfx_xa_surface_redefine - wrapper around xa_surface_redefine
*
* @vpix: Pointer to the struct vmwgfx_saa_pixmap the surface is attached to.
* @srf: The surface.
* @width: New width.
* @height: New height.
* @depth: New pixel depth.
* @stype: New surface type.
* @rgb_format: New rgb format.
* @new_flags: New surface flags.
* @copy_contents: Copy contents if new backing store is allocated.
*
* This is a wrapper that prints out an error message if the backing store
* of an active scanout surface is changed.
*/
Bool
vmwgfx_xa_surface_redefine(struct vmwgfx_saa_pixmap *vpix,
struct xa_surface *srf,
int width,
int height,
int depth,
enum xa_surface_type stype,
enum xa_formats rgb_format,
unsigned int new_flags,
int copy_contents)
{
uint32_t handle, new_handle, dummy;
Bool have_handle = FALSE;
if (!WSBMLISTEMPTY(&vpix->scanout_list))
have_handle = (_xa_surface_handle(srf, &handle, &dummy) == XA_ERR_NONE);
if (xa_surface_redefine(srf, width, height, depth, stype, rgb_format,
new_flags, copy_contents) != XA_ERR_NONE)
return FALSE;
if (!WSBMLISTEMPTY(&vpix->scanout_list) && have_handle &&
_xa_surface_handle(srf, &new_handle, &dummy) == XA_ERR_NONE &&
new_handle != handle) {
LogMessage(X_ERROR, "Changed active scanout surface handle.\n");
}
return TRUE;
}
/*
* 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 | XA_FLAG_SHARED;
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 | XA_FLAG_SHARED;
if (vpix->staging_format != xa_surface_format(vpix->hw))
LogMessage(X_INFO, "Changing hardware format.\n");
if (!vmwgfx_xa_surface_redefine(vpix,
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)
{
struct vmwgfx_saa *vsaa =
to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen));
if (!vsaa->is_master)
return FALSE;
return (vmwgfx_hw_dri2_stage(pixmap, depth) &&
vmwgfx_hw_commit(pixmap) &&
vmwgfx_hw_validate(pixmap, NULL));
}