diff options
author | Thomas Hellstrom <thellstrom@vmware.com> | 2014-11-17 19:18:15 +0100 |
---|---|---|
committer | Thomas Hellstrom <thellstrom@vmware.com> | 2014-11-18 19:53:27 +0100 |
commit | 3f7defa8dc595342e2502206ed2006f2be20a884 (patch) | |
tree | 07d0d86168fb4b9ba4cc1d1803e35c061e6fa719 /vmwgfx/vmwgfx_tex_video.c | |
parent | 4664412d7a5266d2b392957406b34abc5db95e48 (diff) |
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>
Diffstat (limited to 'vmwgfx/vmwgfx_tex_video.c')
-rw-r--r-- | vmwgfx/vmwgfx_tex_video.c | 275 |
1 files changed, 267 insertions, 8 deletions
diff --git a/vmwgfx/vmwgfx_tex_video.c b/vmwgfx/vmwgfx_tex_video.c index 0803a99..18eb9dd 100644 --- a/vmwgfx/vmwgfx_tex_video.c +++ b/vmwgfx/vmwgfx_tex_video.c @@ -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; |