diff options
author | Zhenyu Wang <zhenyu.z.wang@intel.com> | 2009-03-03 22:55:35 +0800 |
---|---|---|
committer | Zhenyu Wang <zhenyu.z.wang@intel.com> | 2009-03-03 22:55:35 +0800 |
commit | 42e34e90e2e4048b38481cab61cef46f932eada7 (patch) | |
tree | f30be7ebf912daedb9dd17436ca80aef4ed45bc4 /src/i830_tv.c | |
parent | aa9da5e393c804019720503fe58bdd247fe1eabd (diff) |
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.
Diffstat (limited to 'src/i830_tv.c')
-rw-r--r-- | 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 e7766515..1e3cf7b6 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))); { @@ -1496,6 +1582,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 "BRIGHTNESS" +#define TV_BRIGHTNESS_DEFAULT 128 /* bias */ +static Atom brightness_atom; +#define TV_CONTRAST_NAME "CONTRAST" +#define TV_CONTRAST_DEFAULT 0x40 +#define TV_CONTRAST_DEFAULT_945G 0x60 +static Atom contrast_atom; +#define TV_SATURATION_NAME "SATURATION" +#define TV_SATURATION_DEFAULT 0x40 +#define TV_SATURATION_DEFAULT_945G 0x60 +static Atom saturation_atom; +#define TV_HUE_NAME "HUE" +#define TV_HUE_DEFAULT 0 +static Atom hue_atom; + static Bool i830_tv_format_set_property (xf86OutputPtr output) { @@ -1541,6 +1647,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 @@ -1548,10 +1710,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 @@ -1599,6 +1761,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 */ } @@ -1703,6 +1882,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; } |