From 46ea3f9a4c58e4fc065b7be7e3942e7163f4f7a7 Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Mon, 23 Feb 2009 23:39:41 +0800 Subject: [PATCH] TV: add property control for TV attributes This is based on Jesse's origin patch for bug #12763. But export integer range to user instead of hardware float point format, and fix different real format on 965G and 945G for contrast and saturation. --- src/i830_tv.c | 211 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 201 insertions(+), 10 deletions(-) diff --git a/src/i830_tv.c b/src/i830_tv.c index 9b24055..804e182 100644 --- a/src/i830_tv.c +++ b/src/i830_tv.c @@ -59,6 +59,10 @@ struct i830_tv_priv { Bool force_type; char *tv_format; int margin[4]; + uint8_t brightness; + uint8_t contrast; + uint8_t saturation; + uint8_t hue; uint32_t save_TV_H_CTL_1; uint32_t save_TV_H_CTL_2; uint32_t save_TV_H_CTL_3; @@ -1020,6 +1024,96 @@ i830_float_to_luma (float f) return ret; } +static uint8_t +float_to_float_2_6(float fin) +{ + uint8_t exp; + uint8_t mant; + float f = fin; + uint32_t tmp; + + if (f < 0) f = -f; + + tmp = f; + for (exp = 0; exp <= 3 && tmp > 0; exp++) + tmp /= 2; + + mant = (f * (1 << 6) + 0.5); + mant >>= exp; + if (mant > (1 << 6)) + mant = (1 << 6) - 1; + + return (exp << 6) | mant; +} + +static uint8_t +float_to_fix_2_6(float f) +{ + uint8_t ret; + + ret = f * (1 << 6); + return ret; +} + +static void +i830_tv_update_brightness(I830Ptr pI830, uint8_t brightness) +{ + /* brightness in 2's comp value */ + uint32_t val = INREG(TV_CLR_KNOBS) & ~TV_BRIGHTNESS_MASK; + int8_t bri = brightness - 128; /* remove bias */ + + val |= (bri << TV_BRIGHTNESS_SHIFT) & TV_BRIGHTNESS_MASK; + OUTREG(TV_CLR_KNOBS, val); +} + +static void +i830_tv_update_contrast(I830Ptr pI830, uint8_t contrast) +{ + uint32_t val = INREG(TV_CLR_KNOBS) & ~TV_CONTRAST_MASK;; + float con; + uint8_t c; + + if (IS_I965G(pI830)) { + /* 2.6 fixed point */ + con = 3.0 * ((float) contrast / 255); + c = float_to_fix_2_6(con); + } else { + /* 2.6 floating point */ + con = 8.875 * ((float) contrast / 255); + c = float_to_float_2_6(con); + } + val |= (c << TV_CONTRAST_SHIFT) & TV_CONTRAST_MASK; + OUTREG(TV_CLR_KNOBS, val); +} + +static void +i830_tv_update_saturation(I830Ptr pI830, uint8_t saturation) +{ + uint32_t val = INREG(TV_CLR_KNOBS) & ~TV_SATURATION_MASK; + float sat; + uint8_t s; + + /* same as contrast */ + if (IS_I965G(pI830)) { + sat = 3.0 * ((float) saturation / 255); + s = float_to_fix_2_6(sat); + } else { + sat = 8.875 * ((float) saturation / 255); + s = float_to_float_2_6(sat); + } + val |= (s << TV_SATURATION_SHIFT) & TV_SATURATION_MASK; + OUTREG(TV_CLR_KNOBS, val); +} + +static void +i830_tv_update_hue(I830Ptr pI830, uint8_t hue) +{ + uint32_t val = INREG(TV_CLR_KNOBS) & ~TV_HUE_MASK; + + val |= (hue << TV_HUE_SHIFT) & TV_HUE_MASK; + OUTREG(TV_CLR_KNOBS, val); +} + static void i830_tv_mode_set(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode) @@ -1181,14 +1275,6 @@ i830_tv_mode_set(xf86OutputPtr output, DisplayModePtr mode, (i830_float_to_csc(color_conversion->bv) << 16) | (i830_float_to_luma(color_conversion->av))); - if (IS_I965G(pI830)) { - /* 2.6 fixed point value for contrast and saturation modifier, - use 1 as default */ - OUTREG(TV_CLR_KNOBS, 0x00404000); - } else { - /* 915/945 uses 2 bits exponent and 6 bits mantissa format */ - OUTREG(TV_CLR_KNOBS, 0x00606000); - } OUTREG(TV_CLR_LEVEL, ((video_levels->black << TV_BLACK_LEVEL_SHIFT) | (video_levels->blank << TV_BLANK_LEVEL_SHIFT))); { @@ -1492,6 +1578,26 @@ static char *margin_names[4] = { "LEFT", "TOP", "RIGHT", "BOTTOM" }; +/** + * contrast and saturation has different format on 915/945 with 965. + * On 915/945, it's 2.6 floating point number. + * On 965, it's 2.6 fixed point number. + */ +#define TV_BRIGHTNESS_NAME "TV_BRIGHTNESS" +#define TV_BRIGHTNESS_DEFAULT 128 /* bias */ +static Atom brightness_atom; +#define TV_CONTRAST_NAME "TV_CONTRAST" +#define TV_CONTRAST_DEFAULT 0x40 +#define TV_CONTRAST_DEFAULT_945G 0x60 +static Atom contrast_atom; +#define TV_SATURATION_NAME "TV_SATURATION" +#define TV_SATURATION_DEFAULT 0x40 +#define TV_SATURATION_DEFAULT_945G 0x60 +static Atom saturation_atom; +#define TV_HUE_NAME "TV_HUE" +#define TV_HUE_DEFAULT 0 +static Atom hue_atom; + static Bool i830_tv_format_set_property (xf86OutputPtr output) { @@ -1537,6 +1643,62 @@ i830_tv_format_configure_property (xf86OutputPtr output) num_atoms, (INT32 *) current_atoms); } +static void +i830_tv_color_set_property(xf86OutputPtr output, Atom property, + uint8_t val) +{ + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_tv_priv *dev_priv = intel_output->dev_priv; + + if (property == brightness_atom) { + dev_priv->brightness = val; + i830_tv_update_brightness(pI830, val); + } else if (property == contrast_atom) { + dev_priv->contrast = val; + i830_tv_update_contrast(pI830, val); + } else if (property == saturation_atom) { + dev_priv->saturation = val; + i830_tv_update_saturation(pI830, val); + } else if (property == hue_atom) { + dev_priv->hue = val; + i830_tv_update_hue(pI830, val); + } +} + +static void +i830_tv_color_create_property(xf86OutputPtr output, Atom *property, + char *name, int name_len, uint8_t val) +{ + ScrnInfoPtr pScrn = output->scrn; + INT32 range[2]; + int err = 0; + + *property = MakeAtom(name, name_len - 1, TRUE); + range[0] = 0; + range[1] = 255; + err = RRConfigureOutputProperty(output->randr_output, *property, + FALSE, TRUE, FALSE, 2, range); + if (err != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "RRConfigureOutputProperty error, %d\n", err); + goto out; + } + /* Set the current value */ + i830_tv_color_set_property(output, *property, val); + + err = RRChangeOutputProperty(output->randr_output, *property, + XA_INTEGER, 32, PropModeReplace, 1, &val, + FALSE, FALSE); + if (err != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "RRChangeOutputProperty error, %d\n", err); + } +out: + return; +} + #endif /* RANDR_12_INTERFACE */ static void @@ -1544,10 +1706,10 @@ i830_tv_create_resources(xf86OutputPtr output) { #ifdef RANDR_12_INTERFACE ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); I830OutputPrivatePtr intel_output = output->driver_private; struct i830_tv_priv *dev_priv = intel_output->dev_priv; - int err; - int i; + int err, i; /* Set up the tv_format property, which takes effect on mode set * and accepts strings that match exactly @@ -1595,6 +1757,23 @@ i830_tv_create_resources(xf86OutputPtr output) xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "RRChangeOutputProperty error, %d\n", err); } + + i830_tv_color_create_property(output, &brightness_atom, + TV_BRIGHTNESS_NAME, + sizeof(TV_BRIGHTNESS_NAME), + TV_BRIGHTNESS_DEFAULT); + i830_tv_color_create_property(output, &contrast_atom, + TV_CONTRAST_NAME, + sizeof(TV_CONTRAST_NAME), + IS_I965G(pI830) ? TV_CONTRAST_DEFAULT : + TV_CONTRAST_DEFAULT_945G); + i830_tv_color_create_property(output, &saturation_atom, + TV_SATURATION_NAME, + sizeof(TV_SATURATION_NAME), + IS_I965G(pI830) ? TV_SATURATION_DEFAULT : + TV_SATURATION_DEFAULT_945G); + i830_tv_color_create_property(output, &hue_atom, TV_HUE_NAME, + sizeof(TV_HUE_NAME), TV_HUE_DEFAULT); #endif /* RANDR_12_INTERFACE */ } @@ -1699,6 +1878,18 @@ i830_tv_set_property(xf86OutputPtr output, Atom property, return TRUE; } } + if (property == brightness_atom || property == contrast_atom || + property == saturation_atom || property == hue_atom) { + uint8_t val; + + /* Make sure value is sane */ + if (value->type != XA_INTEGER || value->format != 32 || + value->size != 1) + return FALSE; + + memcpy (&val, value->data, 1); + i830_tv_color_set_property(output, property, val); + } return TRUE; } -- 1.5.6.5