vmware/vmwgfx: Make large Xv video blits cheaper

As screens grow larger, attempt to make large Xv video blits cheaper by
performing the color conversion and scaling in two steps:

1) Color conversion which has a 4x4 matrix multiplication shader is performed
   to a bounce buffer the size of which is never larger than the source image.
2) Scaling is performed as a src composite blit to the destination image with
   a simple copy shader.

This split is done only if the destination image is substantially larger than
the source image / bounce buffer

Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Sinclair Yeh <syeh@vmware.com>
This commit is contained in:
Thomas Hellstrom
2014-11-17 19:18:15 +01:00
parent 4664412d7a
commit 3f7defa8dc

View File

@@ -113,6 +113,12 @@ struct xorg_xv_port_priv {
int current_set;
struct xa_surface *yuv[2][3];
struct xa_surface *bounce;
struct xa_box bounce_box;
struct xa_picture *src_pic;
struct xa_picture *dst_pic;
struct xa_composite *comp;
int drm_fd;
Bool hdtv;
@@ -178,6 +184,27 @@ vmwgfx_update_conversion_matrix(struct xorg_xv_port_priv *priv)
cm[15] = 1.f;
}
/**
* vmwgfx_video_free_comp - free members used for composite bounce blit
*
* @priv: Pointer to the port private
*
* Frees any port priv resources allocated for a composite bounce blit.
*/
static void
vmwgfx_video_free_comp(struct xorg_xv_port_priv *priv)
{
if (priv->dst_pic)
free(priv->dst_pic);
if (priv->src_pic)
free(priv->src_pic);
if (priv->comp)
free(priv->comp);
priv->dst_pic = NULL;
priv->src_pic = NULL;
priv->comp = NULL;
}
static void
stop_video(ScrnInfoPtr pScrn, pointer data, Bool shutdown)
@@ -195,6 +222,7 @@ stop_video(ScrnInfoPtr pScrn, pointer data, Bool shutdown)
xa_fence_destroy(priv->fence);
priv->fence = NULL;
vmwgfx_video_free_comp(priv);
for (i=0; i<3; ++i) {
for (j=0; j<2; ++j) {
@@ -202,6 +230,10 @@ stop_video(ScrnInfoPtr pScrn, pointer data, Bool shutdown)
xa_surface_destroy(priv->yuv[j][i]);
priv->yuv[j][i] = NULL;
}
if (priv->bounce) {
xa_surface_destroy(priv->bounce);
priv->bounce = NULL;
}
}
}
}
@@ -331,6 +363,174 @@ check_yuv_surfaces(struct xorg_xv_port_priv *priv, int id,
return Success;
}
/**
* vmwgfx_video_setup_comp - Set up port priv members for a composite
* bounce blit
*
* @priv: Pointer to the port priv.
* @format: XA format of the destination drawable surface.
*
* Tries to allocate and set up port priv resources to perform a composite
* bounce blit (except the bounce surface itself). On failure, all resources
* are freed. On success, TRUE is returned and @priv::comp is non-NULL. If
* resources are already allocated, update them for the current @format.
*/
static Bool
vmwgfx_video_setup_comp(struct xorg_xv_port_priv *priv, enum xa_formats format)
{
const struct xa_composite_allocation *alloc;
struct xa_picture *pic;
if (priv->comp) {
if (priv->src_pic->pict_format != format) {
priv->src_pic->pict_format = format;
priv->dst_pic->pict_format = format;
if (xa_composite_check_accelerated(priv->comp) != XA_ERR_NONE) {
vmwgfx_video_free_comp(priv);
return FALSE;
}
}
return TRUE;
}
alloc = xa_composite_allocation();
priv->comp = calloc(1, alloc->xa_composite_size);
priv->src_pic = calloc(1, alloc->xa_picture_size);
priv->dst_pic = calloc(1, alloc->xa_picture_size);
if (!priv->comp || !priv->src_pic || !priv->dst_pic) {
vmwgfx_video_free_comp(priv);
return FALSE;
}
pic = priv->src_pic;
pic->pict_format = format;
pic->wrap = xa_wrap_clamp_to_border;
pic->filter = xa_filter_linear;
*priv->dst_pic = *pic;
priv->comp->src = priv->src_pic;
priv->comp->dst = priv->dst_pic;
priv->comp->op = xa_op_src;
priv->comp->no_solid = 1;
if (xa_composite_check_accelerated(priv->comp) != XA_ERR_NONE) {
vmwgfx_video_free_comp(priv);
return FALSE;
}
return TRUE;
}
/**
* vmwgfx_video_setup_coord_matrix - Set up a bounce - to destination
* transformation matrix
*
* @src_x: Upper left corner of source image as given to putImage.
* @src_y: Upper left corner of source image as given to putImage.
* @src_w: Width of source image.
* @src_h: Height of source image.
* @dst_x: Upper left corner of destination image as given to putImage.
* @dst_y: Upper left corner of destination image as given to putImage.
* @dst_w: Width of destination image.
* @dst_h: Height of destination image.
* @bounce_w: Width of bounce surface.
* @bounce_h: Height of bounce surface.
* @mat: Pointer to transformation matrix.
*
* Computes a transformation matrix that can be used by the XA composite API
* to transform between the destination coordinate space and the bounce
* surface coordinate space. Scaling and translation.
*/
static void
vmwgfx_video_setup_coord_matrix(int src_x, int src_y, int src_w, int src_h,
int dst_x, int dst_y, int dst_w, int dst_h,
int bounce_w, int bounce_h,
float *mat)
{
if (dst_w == 0 || dst_h == 0 || src_w == 0 || src_h == 0) {
mat[0] = mat[6] = 0.;
mat[4] = mat[7] = 0.;
mat[8] = 1.f;
return;
}
mat[0] = (float) bounce_w / (float) dst_w;
mat[6] = (float) src_x * (float) bounce_w / (float) src_w -
(float) dst_x * mat[0];
mat[4] = (float) bounce_h / (float) dst_h;
mat[7] = (float) src_y * (float) bounce_h / (float) src_h -
(float) dst_y * mat[4];
mat[8] = 1.f;
}
/**
* vmwgfx_video_bounce_surface: (Re)Allocate a bounce surface if desired.
*
* @priv: Pointer to the port private.
* @d_with: Width of destination image.
* @d_height: Height of destination image.
* @width: Width of source video image.
* @height: Height of source video image.
* @dst_format: Format of destination drawable surface.
*
* If the destination video image is a suitable factor larger than the source
* video image. Allocate a bounce RGB surface that will be the target of the
* more expensive color conversion blit, and source of the scaling blit.
*/
static Bool
vmwgfx_video_bounce_surface(struct xorg_xv_port_priv *priv,
int d_width, int d_height,
int width, int height,
enum xa_formats dst_format)
{
float bounce_area, dst_area;
if (d_width < width)
width = d_width;
if (d_height < height)
height = d_height;
bounce_area = (float) width * (float) height;
dst_area = (float) d_width * (float) d_height;
if (dst_area > bounce_area * 1.5f &&
vmwgfx_video_setup_comp(priv, dst_format)) {
if (!priv->bounce) {
priv->bounce = xa_surface_create(priv->xat, width, height,
xa_format_depth(dst_format),
xa_format_type(dst_format),
dst_format, XA_FLAG_RENDER_TARGET);
} else {
if (xa_surface_redefine(priv->bounce, width, height,
xa_format_depth(dst_format),
xa_format_type(dst_format),
dst_format,
XA_FLAG_RENDER_TARGET, 0) != XA_ERR_NONE) {
xa_surface_destroy(priv->bounce);
priv->bounce = NULL;
}
}
} else {
xa_surface_destroy(priv->bounce);
priv->bounce = NULL;
}
if (priv->bounce) {
priv->bounce_box.x1 = 0;
priv->bounce_box.x2 = width;
priv->bounce_box.y1 = 0;
priv->bounce_box.y2 = height;
}
return TRUE;
}
static int
query_image_attributes(ScrnInfoPtr pScrn,
int id,
@@ -480,6 +680,7 @@ display_video(ScreenPtr pScreen, struct xorg_xv_port_priv *pPriv, int id,
RegionPtr dstRegion,
int src_x, int src_y, int src_w, int src_h,
int dst_x, int dst_y, int dst_w, int dst_h,
int width, int height,
PixmapPtr pPixmap)
{
struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pPixmap);
@@ -521,15 +722,72 @@ display_video(ScreenPtr pScreen, struct xorg_xv_port_priv *pPriv, int id,
pPriv->fence = NULL;
}
(void) vmwgfx_video_bounce_surface(pPriv, dst_w, dst_h, width, height,
xa_surface_format(vpix->hw));
DamageRegionAppend(&pPixmap->drawable, dstRegion);
blit_ret = xa_yuv_planar_blit(pPriv->r, src_x, src_y, src_w, src_h,
dst_x, dst_y, dst_w, dst_h,
(struct xa_box *)REGION_RECTS(dstRegion),
REGION_NUM_RECTS(dstRegion),
pPriv->cm,
vpix->hw,
pPriv->yuv[pPriv->current_set ]);
if (pPriv->bounce) {
BoxPtr b;
int i;
/*
* If we have a bounce buffer, First perform a (potentially down-
* scaling) color conversion blit with an expensive shader.
*/
blit_ret = xa_yuv_planar_blit(pPriv->r, 0, 0, src_w, src_h,
src_x, src_y,
pPriv->bounce_box.x2,
pPriv->bounce_box.y2,
&pPriv->bounce_box, 1,
pPriv->cm,
pPriv->bounce,
pPriv->yuv[pPriv->current_set]);
if (blit_ret)
goto out_blit;
/*
* Then an upscaling blit with a cheap shader. Note that we never
* scale up a dimenstion that was previously downscaled in the color
* conversion blit.
*/
pPriv->src_pic->srf = pPriv->bounce;
pPriv->dst_pic->srf = vpix->hw;
vmwgfx_video_setup_coord_matrix(src_x, src_y, src_w, src_h,
dst_x, dst_y, dst_w, dst_h,
pPriv->bounce_box.x2,
pPriv->bounce_box.y2,
pPriv->src_pic->transform);
pPriv->src_pic->has_transform = 1;
if (xa_composite_prepare(pPriv->r, pPriv->comp) != XA_ERR_NONE) {
blit_ret = 1;
goto out_blit;
}
b = REGION_RECTS(dstRegion);
for (i = 0; i < REGION_NUM_RECTS(dstRegion); ++i, ++b) {
xa_composite_rect(pPriv->r, b->x1, b->y1, 0, 0,
b->x1, b->y1, b->x2 - b->x1,
b->y2 - b->y1);
}
xa_composite_done(pPriv->r);
} else {
/*
* Perform color conversion and scaling in the same blit.
*/
blit_ret = xa_yuv_planar_blit(pPriv->r, src_x, src_y, src_w, src_h,
dst_x, dst_y, dst_w, dst_h,
(struct xa_box *)REGION_RECTS(dstRegion),
REGION_NUM_RECTS(dstRegion),
pPriv->cm,
vpix->hw,
pPriv->yuv[pPriv->current_set ]);
}
out_blit:
saa_pixmap_dirty(pPixmap, TRUE, dstRegion);
DamageRegionProcessPending(&pPixmap->drawable);
@@ -597,7 +855,8 @@ put_image(ScrnInfoPtr pScrn,
display_video(pScrn->pScreen, pPriv, id, clipBoxes,
src_x, src_y, src_w, src_h,
drw_x, drw_y,
drw_w, drw_h, pPixmap);
drw_w, drw_h,
width, height, pPixmap);
pPriv->current_set = (pPriv->current_set + 1) & 1;
return Success;