diff options
Diffstat (limited to 'vmwgfx/vmwgfx_tex_video.c')
-rw-r--r-- | vmwgfx/vmwgfx_tex_video.c | 105 |
1 files changed, 78 insertions, 27 deletions
diff --git a/vmwgfx/vmwgfx_tex_video.c b/vmwgfx/vmwgfx_tex_video.c index 801b066..b2c5472 100644 --- a/vmwgfx/vmwgfx_tex_video.c +++ b/vmwgfx/vmwgfx_tex_video.c @@ -45,36 +45,28 @@ #define RES_720P_Y 720 -/* The ITU-R BT.601 conversion matrix for SDTV. */ -/* original, matrix, but we transpose it to - * make the shader easier -static const float bt_601[] = { - 1.0, 0.0, 1.4075, , - 1.0, -0.3455, -0.7169, 0, - 1.0, 1.7790, 0., 0, -};*/ +#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) + +/* + * ITU-R BT.601, BT.709 transfer matrices. + * [R', G', B'] values are in the range [0, 1], Y' is in the range [0,1] + * and [Pb, Pr] components are in the range [-0.5, 0.5]. + * + * The matrices are transposed to fit the xa conversion matrix format. + */ + static const float bt_601[] = { - 1.0, 1.0, 1.0, 0.5, - 0.0, -0.3455, 1.7790, 0, - 1.4075, -0.7169, 0., 0, + 1.f, 1.f, 1.f, 0.f, + 0.f, -0.344136f, 1.772f, 0.f, + 1.402f, -0.714136f, 0.f, 0.f }; -/* The ITU-R BT.709 conversion matrix for HDTV. */ -/* original, but we transpose to make the conversion - * in the shader easier static const float bt_709[] = { - 1.0, 0.0, 1.581, 0, - 1.0, -0.1881, -0.47, 0, - 1.0, 1.8629, 0., 0, -};*/ -static const float bt_709[] = { - 1.0, 1.0, 1.0, 0.5, - 0.0, -0.1881, 1.8629, 0, - 1.581,-0.47 , 0.0, 0, + 1.f, 1.f, 1.f, 0.f, + 0.f, -0.187324f, 1.8556f, 0.f, + 1.5748f, -0.468124f, 0.f, 0.f }; -#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) - static Atom xvBrightness, xvContrast; #define NUM_TEXTURED_ATTRIBUTES 2 @@ -119,8 +111,56 @@ struct xorg_xv_port_priv { struct xa_surface *yuv[3]; int drm_fd; + + Bool hdtv; + float uv_offset; + float uv_scale; + float y_offset; + float y_scale; + float rgb_offset; + float rgb_scale; + float cm[16]; }; +/* + * vmwgfx_update_conversion_matrix - Compute the effective color conversion + * matrix. + * + * Applies yuv- and resulting rgb scales and offsets to compute the correct + * color conversion matrix. These scales and offsets are properties of the + * video stream (and might in the future be adjusted using XV properties as well). + */ +static void +vmwgfx_update_conversion_matrix(struct xorg_xv_port_priv *priv) +{ + int i; + float *cm = priv->cm; + + memcpy(cm, ((priv->hdtv) ? bt_709 : bt_601), sizeof(bt_601)); + + /* + * Adjust for yuv scales in input and rgb scale in the converted output. + */ + + for(i = 0; i < 3; ++i) { + cm[i] *= (priv->y_scale*priv->rgb_scale); + cm[i+4] *= (priv->uv_scale*priv->rgb_scale); + cm[i+8] *= (priv->uv_scale*priv->rgb_scale); + } + + /* + * Adjust for yuv offsets in input and rgb offset in the converted output. + */ + for (i = 0; i < 3; ++i) + cm[i+12] = -cm[i]*priv->y_offset - (cm[i+4] + cm[i+8])*priv->uv_offset + - priv->rgb_offset*priv->rgb_scale; + + /* + * Alpha is 1, unconditionally. + */ + cm[15] = 1.f; +} + static void stop_video(ScrnInfoPtr pScrn, pointer data, Bool shutdown) @@ -451,7 +491,6 @@ display_video(ScreenPtr pScreen, struct xorg_xv_port_priv *pPriv, int id, RegionRec reg; int ret = BadAlloc; int blit_ret; - const float *conv_matrix; REGION_NULL(pScreen, ®); @@ -459,7 +498,10 @@ display_video(ScreenPtr pScreen, struct xorg_xv_port_priv *pPriv, int id, goto out_no_dst; hdtv = ((src_w >= RES_720P_X) && (src_h >= RES_720P_Y)); - conv_matrix = (hdtv ? bt_709 : bt_601); + if (hdtv != pPriv->hdtv) { + pPriv->hdtv = hdtv; + vmwgfx_update_conversion_matrix(pPriv); + } #ifdef COMPOSITE @@ -489,7 +531,7 @@ display_video(ScreenPtr pScreen, struct xorg_xv_port_priv *pPriv, int id, dst_x, dst_y, dst_w, dst_h, (struct xa_box *)REGION_RECTS(dstRegion), REGION_NUM_RECTS(dstRegion), - conv_matrix, + pPriv->cm, vpix->hw, pPriv->yuv); saa_pixmap_dirty(pPixmap, TRUE, dstRegion); @@ -579,6 +621,15 @@ port_priv_create(struct xa_tracker *xat, struct xa_context *r, priv->xat = xat; priv->drm_fd = drm_fd; REGION_NULL(pScreen, &priv->clip); + priv->hdtv = FALSE; + priv->uv_offset = 0.5f; + priv->uv_scale = 1.f; + priv->y_offset = 0.f; + priv->y_scale = 1.f; + priv->rgb_offset = 0.f; + priv->rgb_scale = 1.f; + + vmwgfx_update_conversion_matrix(priv); return priv; } |