mirror of
https://github.com/X11Libre/xf86-video-vmware.git
synced 2026-03-24 01:24:37 +00:00
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:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user