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.
This commit is contained in:
Zhenyu Wang 2009-03-03 22:55:35 +08:00
parent aa9da5e393
commit 42e34e90e2
2 changed files with 225 additions and 10 deletions

View File

@ -272,6 +272,30 @@ Integrated TV output. Available properties include:
.TP 2
Adjusting these properties allows you to control the placement of your TV output buffer on the screen. The options with the same name can also be set in xorg.conf with integer value.
.PP
.B BRIGHTNESS
- TV brightness, range 0-255
.TP 2
Adjust TV brightness, default value is 128.
.PP
.B CONTRAST
- TV contrast, range 0-255
.TP 2
Adjust TV contrast, default value is 1.0 in chipset specific format.
.PP
.B SATURATION
- TV saturation, range 0-255
.TP 2
Adjust TV saturation, default value is 1.0 in chipset specific format.
.PP
.B HUE
- TV hue, range 0-255
.TP 2
Adjust TV hue, default value is 0.
.PP
.B TV_FORMAT
- output standard

View File

@ -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;
}