vmwgfx: Try to sort out format handling with composite.

Try to catch all cases where we have to do readbacks or format conversions
due to composite formats not being compatible with ordinary accel formats.

Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
This commit is contained in:
Thomas Hellstrom
2011-07-01 11:28:52 +02:00
parent 8a21da8eaa
commit 8a9997f060
7 changed files with 704 additions and 232 deletions

View File

@@ -21,6 +21,7 @@ vmwgfx_drv_la_SOURCES = \
vmwgfx_ctrl.c \
vmwgfx_ctrl.h \
vmwgfx_xa_composite.c \
vmwgfx_xa_surface.c \
wsbm_util.h

View File

@@ -167,9 +167,8 @@ dri2_do_create_buffer(DrawablePtr pDraw, DRI2Buffer2Ptr buffer, unsigned int for
if (!srf) {
depth = (format) ? vmwgfx_color_format_to_depth(format) :
pDraw->depth;
if (!vmwgfx_pixmap_validate_hw(pPixmap, NULL, depth,
XA_FLAG_SHARED | XA_FLAG_RENDER_TARGET,
0))
if (!vmwgfx_hw_dri2_validate(pPixmap, depth))
return FALSE;
srf = vpix->hw;
@@ -308,12 +307,9 @@ dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion,
/* pixmap glXWaitX */
if (pSrcBuffer->attachment == DRI2BufferFrontLeft &&
pDestBuffer->attachment == DRI2BufferFakeFrontLeft) {
LogMessage(X_INFO, "dri2 Validate hw.\n");
vmwgfx_pixmap_validate_hw(src_priv->pPixmap, NULL,
0,
XA_FLAG_SHARED | XA_FLAG_RENDER_TARGET,
0);
return;
if (!vmwgfx_hw_dri2_validate(src_priv->pPixmap, 0))
return;
}
/* pixmap glXWaitGL */
if (pDestBuffer->attachment == DRI2BufferFrontLeft &&

View File

@@ -32,60 +32,7 @@
#include <xa_context.h>
#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)
struct vmwgfx_saa {
struct saa_driver driver;
struct vmwgfx_dma_ctx *ctx;
struct xa_tracker *xat;
struct xa_context *xa_ctx;
ScreenPtr pScreen;
int drm_fd;
struct vmwgfx_saa_pixmap *src_vpix;
struct vmwgfx_saa_pixmap *dst_vpix;
Bool present_copy;
Bool diff_valid;
int xdiff;
int ydiff;
RegionRec present_region;
uint32_t src_handle;
Bool can_optimize_dma;
void (*present_flush) (ScreenPtr pScreen);
struct _WsbmListHead sync_x_list;
struct vmwgfx_composite *vcomp;
};
static inline struct vmwgfx_saa *
to_vmwgfx_saa(struct saa_driver *driver) {
return (struct vmwgfx_saa *) driver;
}
static enum xa_formats
vmwgfx_choose_xa_format(unsigned int depth)
{
/*
* For a given depth, choose the same format as the
* dri state tracker.
*/
switch(depth) {
case 32:
case 24: /* The dri state tracker never uses 24. */
return xa_format_a8r8g8b8;
case 16:
return xa_format_r5g6b5;
case 15: /* No dri. */
return xa_format_x1r5g5b5;
default:
break;
}
return xa_format_unknown;
}
#include "vmwgfx_saa_priv.h"
static Bool
vmwgfx_pixmap_add_damage(PixmapPtr pixmap)
@@ -486,6 +433,33 @@ vmwgfx_create_pixmap(struct saa_driver *driver, struct saa_pixmap *spix,
return TRUE;
}
Bool
vmwgfx_hw_kill(struct vmwgfx_saa *vsaa,
struct saa_pixmap *spix)
{
struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
/*
* Read back any dirty regions from hardware.
*/
if (!vmwgfx_download_from_hw(&vsaa->driver, spix->pixmap,
&spix->dirty_hw))
return FALSE;
xa_surface_destroy(vpix->hw);
vpix->hw = NULL;
/*
* Remove damage tracking if this is not a scanout pixmap.
*/
if (WSBMLISTEMPTY(&vpix->scanout_list))
vmwgfx_pixmap_remove_damage(spix->pixmap);
return TRUE;
}
void
vmwgfx_flush_dri2(ScreenPtr pScreen)
{
@@ -530,51 +504,6 @@ vmwgfx_destroy_pixmap(struct saa_driver *driver, PixmapPtr pixmap)
LogMessage(X_ERROR, "Incorrect dri2 front count.\n");
}
static Bool
vmwgfx_pixmap_create_hw(struct vmwgfx_saa *vsaa,
PixmapPtr pixmap, unsigned int depth,
unsigned int flags)
{
struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
struct xa_surface *hw;
if (!vsaa->xat)
return FALSE;
if (vpix->hw)
return TRUE;
if (!depth)
depth = pixmap->drawable.depth;
hw = xa_surface_create(vsaa->xat,
pixmap->drawable.width,
pixmap->drawable.height,
depth,
xa_type_argb,
vmwgfx_choose_xa_format(depth),
XA_FLAG_RENDER_TARGET | flags);
if (hw == NULL)
return FALSE;
if ((vpix->gmr || vpix->malloc) && !vmwgfx_pixmap_add_damage(pixmap))
goto out_no_damage;
/*
* Even if we don't have a GMR yet, indicate that when needed it
* should be created.
*/
vpix->hw = hw;
vpix->backing |= VMWGFX_PIX_SURFACE;
vmwgfx_pixmap_free_storage(vpix);
return TRUE;
out_no_damage:
xa_surface_destroy(hw);
return FALSE;
}
/**
@@ -582,79 +511,6 @@ out_no_damage:
* Makes sure we have a surface with valid contents.
*/
Bool
vmwgfx_pixmap_validate_hw(PixmapPtr pixmap, RegionPtr region,
unsigned int depth,
unsigned int add_flags,
unsigned int remove_flags)
{
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);
RegionRec intersection;
if (!vsaa->xat)
return FALSE;
if (vpix->hw) {
if (!depth)
depth = pixmap->drawable.depth;
if (xa_surface_redefine(vpix->hw,
pixmap->drawable.width,
pixmap->drawable.height,
depth,
xa_type_argb,
vmwgfx_choose_xa_format(depth),
XA_FLAG_RENDER_TARGET | add_flags,
remove_flags, 1) != 0)
return FALSE;
} else if (!vmwgfx_pixmap_create_hw(vsaa, pixmap, depth, add_flags))
return FALSE;
if (!vmwgfx_pixmap_present_readback(vsaa, pixmap, region))
return FALSE;
REGION_NULL(vsaa->pScreen, &intersection);
REGION_COPY(vsaa->pScreen, &intersection, &spix->dirty_shadow);
if (vpix->dirty_present)
REGION_UNION(vsaa->pScreen, &intersection, vpix->dirty_present,
&spix->dirty_shadow);
if (spix->damage && REGION_NOTEMPTY(vsaa->pScreen, &intersection)) {
RegionPtr upload = &intersection;
/*
* Check whether we need to upload from GMR.
*/
if (region) {
REGION_INTERSECT(vsaa->pScreen, &intersection, region,
&intersection);
upload = &intersection;
}
if (REGION_NOTEMPTY(vsaa->pScreen, upload)) {
Bool ret = vmwgfx_upload_to_hw(&vsaa->driver, pixmap, upload);
if (ret) {
REGION_SUBTRACT(vsaa->pScreen, &spix->dirty_shadow,
&spix->dirty_shadow, upload);
if (vpix->dirty_present)
REGION_SUBTRACT(vsaa->pScreen, vpix->dirty_present,
vpix->dirty_present, upload);
} else {
REGION_UNINIT(vsaa->pScreen, &intersection);
return FALSE;
}
}
}
REGION_UNINIT(vsaa->pScreen, &intersection);
return TRUE;
}
static void
vmwgfx_copy_stride(uint8_t *dst, uint8_t *src, unsigned int dst_pitch,
unsigned int src_pitch, unsigned int dst_height,
@@ -730,7 +586,7 @@ vmwgfx_pix_resize(PixmapPtr pixmap, unsigned int old_pitch,
if (vpix->hw) {
if (xa_surface_redefine(vpix->hw, draw->width, draw->height,
draw->depth, xa_type_argb,
xa_format_unknown, 0, 0, 1) != 0)
xa_format_unknown, vpix->xa_flags, 1) != 0)
return FALSE;
}
return TRUE;
@@ -858,6 +714,106 @@ vmwgfx_check_hw_contents(struct vmwgfx_saa *vsaa,
REGION_UNINIT(vsaa->pScreen, &intersection);
}
Bool
vmwgfx_create_hw(struct vmwgfx_saa *vsaa,
PixmapPtr pixmap)
{
struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
struct xa_surface *hw;
uint32_t new_flags;
if (!vsaa->xat)
return FALSE;
if (vpix->hw)
return TRUE;
new_flags = (vpix->xa_flags & ~vpix->staging_remove_flags) |
vpix->staging_add_flags;
hw = xa_surface_create(vsaa->xat,
pixmap->drawable.width,
pixmap->drawable.height,
0,
xa_type_other,
vpix->staging_format,
new_flags);
if (hw == NULL)
return FALSE;
vpix->xa_flags = new_flags;
if ((vpix->gmr || vpix->malloc) && !vmwgfx_pixmap_add_damage(pixmap))
goto out_no_damage;
/*
* Even if we don't have a GMR yet, indicate that when needed it
* should be created.
*/
vpix->hw = hw;
vpix->backing |= VMWGFX_PIX_SURFACE;
vmwgfx_pixmap_free_storage(vpix);
return TRUE;
out_no_damage:
xa_surface_destroy(hw);
return FALSE;
}
Bool
vmwgfx_hw_validate(PixmapPtr pixmap, RegionPtr region)
{
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);
RegionRec intersection;
if (!vmwgfx_pixmap_present_readback(vsaa, pixmap, region))
return FALSE;
REGION_NULL(vsaa->pScreen, &intersection);
REGION_COPY(vsaa->pScreen, &intersection, &spix->dirty_shadow);
if (vpix->dirty_present)
REGION_UNION(vsaa->pScreen, &intersection, vpix->dirty_present,
&spix->dirty_shadow);
if (spix->damage && REGION_NOTEMPTY(vsaa->pScreen, &intersection)) {
RegionPtr upload = &intersection;
/*
* Check whether we need to upload from GMR.
*/
if (region) {
REGION_INTERSECT(vsaa->pScreen, &intersection, region,
&intersection);
upload = &intersection;
}
if (REGION_NOTEMPTY(vsaa->pScreen, upload)) {
Bool ret = vmwgfx_upload_to_hw(&vsaa->driver, pixmap, upload);
if (ret) {
REGION_SUBTRACT(vsaa->pScreen, &spix->dirty_shadow,
&spix->dirty_shadow, upload);
if (vpix->dirty_present)
REGION_SUBTRACT(vsaa->pScreen, vpix->dirty_present,
vpix->dirty_present, upload);
} else {
REGION_UNINIT(vsaa->pScreen, &intersection);
return FALSE;
}
}
}
REGION_UNINIT(vsaa->pScreen, &intersection);
return TRUE;
}
static Bool
vmwgfx_copy_prepare(struct saa_driver *driver,
PixmapPtr src_pixmap,
@@ -891,7 +847,7 @@ vmwgfx_copy_prepare(struct saa_driver *driver,
return FALSE;
if (vmwgfx_present_prepare(vsaa, src_vpix, dst_vpix)) {
if (!vmwgfx_pixmap_validate_hw(src_pixmap, src_reg, 0, 0, 0))
if (!vmwgfx_hw_accel_validate(src_pixmap, 0, 0, 0, src_reg))
return FALSE;
vsaa->present_copy = TRUE;
return TRUE;
@@ -900,7 +856,7 @@ vmwgfx_copy_prepare(struct saa_driver *driver,
}
vsaa->present_copy = FALSE;
if (src_vpix->hw != NULL && src_vpix != dst_vpix) {
if (src_vpix != dst_vpix) {
/*
* Use hardware acceleration either if source is partially only
@@ -910,14 +866,43 @@ vmwgfx_copy_prepare(struct saa_driver *driver,
if (!has_dirty_hw && !(has_valid_hw && (dst_vpix->hw != NULL)))
return FALSE;
if (!vmwgfx_pixmap_validate_hw(src_pixmap, src_reg, 0, 0, 0))
/*
* Determine surface formats.
*/
if (!vmwgfx_hw_accel_stage(src_pixmap, 0, XA_FLAG_RENDER_TARGET, 0))
return FALSE;
if (!vmwgfx_pixmap_create_hw(vsaa, dst_pixmap, 0,
XA_FLAG_RENDER_TARGET))
if (!vmwgfx_hw_accel_stage(dst_pixmap, 0, XA_FLAG_RENDER_TARGET, 0))
return FALSE;
if (xa_copy_prepare(vsaa->xa_ctx, dst_vpix->hw, src_vpix->hw) == 0)
return TRUE;
/*
* Create hardware surfaces.
*/
if (!vmwgfx_hw_commit(src_pixmap))
return FALSE;
if (!vmwgfx_hw_commit(dst_pixmap))
return FALSE;
/*
* Setup copy state.
*/
if (xa_copy_prepare(vsaa->xa_ctx, dst_vpix->hw, src_vpix->hw) !=
XA_ERR_NONE)
return FALSE;
/*
* Migrate data.
*/
if (!vmwgfx_hw_validate(src_pixmap, src_reg)) {
xa_copy_done(vsaa->xa_ctx);
return FALSE;
}
return TRUE;
}
return FALSE;
@@ -1077,24 +1062,26 @@ vmwgfx_composite_prepare(struct saa_driver *driver, CARD8 op,
goto out_err;
/*
* Create hw surfaces and migrate data needed for HW compositing.
* Check that we can create the needed hardware surfaces.
*/
if (src_region == NULL)
src_region = &empty;
if (src_pix &&
!vmwgfx_pixmap_validate_hw(src_pix, src_region, 0, 0, 0))
if (src_pix && !vmwgfx_hw_composite_src_stage(src_pix, src_pict->format))
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))
!vmwgfx_hw_composite_src_stage(mask_pix, mask_pict->format))
goto out_err;
if (!vmwgfx_hw_composite_dst_stage(dst_pix, dst_pict->format))
goto out_err;
if (dst_region == NULL)
dst_region = &empty;
if (!vmwgfx_pixmap_validate_hw(dst_pix, dst_region, 0, 0, 0))
/*
* Seems OK. Commit the changes, creating hardware surfaces.
*/
if (src_pix && !vmwgfx_hw_commit(src_pix))
goto out_err;
if (mask_pict && mask_pix && !vmwgfx_hw_commit(mask_pix))
goto out_err;
if (!vmwgfx_hw_commit(dst_pix))
goto out_err;
/*
@@ -1108,9 +1095,26 @@ vmwgfx_composite_prepare(struct saa_driver *driver, CARD8 op,
if (xa_composite_prepare(vsaa->xa_ctx, xa_comp))
goto out_err;
/*
* Migrate data to surfaces, now that we know that the hardware can indeed
* accelerate.
*/
if (src_pix && src_region && !vmwgfx_hw_validate(src_pix, src_region))
goto out_err_migrate;
if (mask_pict && mask_pix && mask_region &&
!vmwgfx_hw_validate(mask_pix, mask_region))
goto out_err_migrate;
if (dst_region && !vmwgfx_hw_validate(dst_pix, dst_region))
goto out_err_migrate;
REGION_UNINIT(pScreen, &empty);
return TRUE;
out_err:
out_err_migrate:
xa_composite_done(vsaa->xa_ctx);
out_err:
REGION_UNINIT(pScreen, &empty);
return FALSE;
}

View File

@@ -54,6 +54,11 @@ struct vmwgfx_saa_pixmap {
int hw_is_dri2_fronts;
struct _WsbmListHead sync_x_head;
struct _WsbmListHead scanout_list;
uint32_t xa_flags;
uint32_t staging_add_flags;
uint32_t staging_remove_flags;
enum xa_formats staging_format;
};
struct vmwgfx_screen_box {
@@ -68,12 +73,6 @@ to_vmwgfx_saa_pixmap(struct saa_pixmap *spix)
return (struct vmwgfx_saa_pixmap *) spix;
}
extern Bool
vmwgfx_pixmap_validate_hw(PixmapPtr pixmap, RegionPtr region,
unsigned int depth,
unsigned int add_flags,
unsigned int remove_flags);
static inline struct vmwgfx_saa_pixmap*
vmwgfx_saa_pixmap(PixmapPtr pix)
{
@@ -99,28 +98,11 @@ 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);
extern Bool
vmwgfx_hw_dri2_validate(PixmapPtr pixmap, unsigned int depth);
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);
vmwgfx_hw_accel_validate(PixmapPtr pixmap, unsigned int depth,
uint32_t add_flags, uint32_t remove_flags,
RegionPtr region);
#endif

122
vmwgfx/vmwgfx_saa_priv.h Normal file
View File

@@ -0,0 +1,122 @@
/*
* 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>
*/
#ifndef _VMWGFX_SAA_PRIV_H_
#define _VMWGFX_SAA_PRIV_H_
#define VMWGFX_PIX_MALLOC (1 << 0)
#define VMWGFX_PIX_GMR (1 << 1)
#define VMWGFX_PIX_SURFACE (1 << 2)
#include <xorg-server.h>
#include <picturestr.h>
#include "vmwgfx_saa.h"
struct vmwgfx_saa {
struct saa_driver driver;
struct vmwgfx_dma_ctx *ctx;
struct xa_tracker *xat;
struct xa_context *xa_ctx;
ScreenPtr pScreen;
int drm_fd;
struct vmwgfx_saa_pixmap *src_vpix;
struct vmwgfx_saa_pixmap *dst_vpix;
Bool present_copy;
Bool diff_valid;
int xdiff;
int ydiff;
RegionRec present_region;
uint32_t src_handle;
Bool can_optimize_dma;
void (*present_flush) (ScreenPtr pScreen);
struct _WsbmListHead sync_x_list;
struct vmwgfx_composite *vcomp;
};
static inline struct vmwgfx_saa *
to_vmwgfx_saa(struct saa_driver *driver) {
return (struct vmwgfx_saa *) driver;
}
/*
* In vmwgfx_saa.c
*/
Bool
vmwgfx_hw_kill(struct vmwgfx_saa *vsaa,
struct saa_pixmap *spix);
Bool
vmwgfx_create_hw(struct vmwgfx_saa *vsaa,
PixmapPtr pixmap);
/*
* vmwgfx_xa_surface.c
*/
enum xa_formats
vmwgfx_xa_format(enum _PictFormatShort format);
Bool
vmwgfx_hw_validate(PixmapPtr pixmap, RegionPtr region);
Bool
vmwgfx_hw_accel_stage(PixmapPtr pixmap, unsigned int depth,
uint32_t add_flags, uint32_t remove_flags);
Bool
vmwgfx_hw_composite_src_stage(PixmapPtr pixmap,
enum _PictFormatShort pict_format);
Bool
vmwgfx_hw_composite_dst_stage(PixmapPtr pixmap,
enum _PictFormatShort pict_format);
Bool
vmwgfx_hw_commit(PixmapPtr pixmap);
/*
* 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

View File

@@ -223,7 +223,7 @@ check_yuv_surfaces(struct xorg_xv_port_priv *priv, int width, int height)
else
ret = xa_surface_redefine(yuv[i], width, height, 8,
xa_type_yuv_component,
xa_format_unknown, 0, 0, 0);
xa_format_unknown, 0, 0);
if (ret || !yuv[i])
return BadAlloc;
@@ -455,7 +455,7 @@ display_video(ScreenPtr pScreen, struct xorg_xv_port_priv *pPriv, int id,
REGION_NULL(pScreen, &reg);
if (!vmwgfx_pixmap_validate_hw(pPixmap, &reg, 0, XA_FLAG_RENDER_TARGET, 0))
if (!vmwgfx_hw_accel_validate(pPixmap, 0, XA_FLAG_RENDER_TARGET, 0, &reg))
goto out_no_dst;
hdtv = ((src_w >= RES_720P_X) && (src_h >= RES_720P_Y));

367
vmwgfx/vmwgfx_xa_surface.c Normal file
View File

@@ -0,0 +1,367 @@
/*
* 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(old_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:
case 24:
return xa_format_a8r8g8b8;
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));
}