[Bug 16001] XVideo gamma curve is wrong at least for r300 chips
bugzilla-daemon at freedesktop.org
bugzilla-daemon at freedesktop.org
Mon May 19 11:09:49 PDT 2008
http://bugs.freedesktop.org/show_bug.cgi?id=16001
--- Comment #5 from Tobias Diedrich <ranma+freedesktop at tdiedrich.de> 2008-05-19 11:09:48 PST ---
(In reply to comment #4)
> Probably the values in the r200 gamma table are just wrong - at least
> datasheets seem to indicate no difference between r200 and r300 in that area
I sure hope these datasheets will also eventually be publicly available. :)
http://www.x.org/docs/AMD/R3xx_3D_Registers.pdf looks promising in that regard.
(And I'd also be interested in Imageon w100 datasheets for my Zaurus, but
that's probably a rather small target group... I really _do_ wonder if this
thing can do proper busmaster DMA)
> I know there were some earlier complaints about gamma tables being wrong, but
> IIRC noone really investigated this a bit deeper.
I never noticed the problem on my r200 and the r300 with my old TFT (6bit S-IPS
panel + dither), but on my new Samsung (8bit S-PVA panel) it much easier to
spot .
> (and for that matter, those segments which are defined on r100 too should be
> the same as far as I can tell, except the offset for the two last segments, and
> they'd indeed pretty much be the same with those shifts).
I suspected that r200 and r300 are the same, but without a r200 to test (I gave
my old r200 away, unfortunately, and also don't have a AGP board here) I didn't
want to touch that part of the code. :)
> > | /* Set gamma */
> > | RADEONWaitForIdleMMIO(pScrn);
> > | ov0_scale_cntl = INREG(RADEON_OV0_SCALE_CNTL) &
> > ~RADEON_SCALER_GAMMA_SEL_MASK;
> > | OUTREG(RADEON_OV0_SCALE_CNTL, ov0_scale_cntl | (gamma << 0x00000005));
> >
> > breaks my overlay (pink screen) for 'gamma' values other than '0'.
> Yup, that's r100 only (the test should be < CHIP_FAMILY_R200 though, not <= -
See above, I wanted to keep the logic for chips other than r300 unchanged.
> Maybe we should try to get rid of the tables entirely for
> r200/r300 and just calculate all the segment values as needed, with arbitrary
> gamma value.
Something like this? (Still my debugging stuff, but works for me :))
--- xserver-xorg-video-ati-6.8.0/src/radeon_video.c 2008-02-19
02:10:46.000000000 +0100
+++ xserver-xorg-video-ati-6.8.0.patched_arbitrary_gamma/src/radeon_video.c
2008-05-16 23:14:53.000000000 +0200
@@ -106,6 +106,7 @@
static Atom xvRedIntensity, xvGreenIntensity, xvBlueIntensity;
static Atom xvContrast, xvHue, xvColor, xvAutopaintColorkey, xvSetDefaults;
static Atom xvGamma, xvColorspace;
+static Atom xvOV0FlagControl, xvOV0Gamma00000f, xvOV0Gamma01001f,
xvOV0Gamma02003f;
static Atom xvCRTC;
static Atom xvEncoding, xvFrequency, xvVolume, xvMute,
xvDecBrightness, xvDecContrast, xvDecHue, xvDecColor,
xvDecSaturation,
@@ -367,7 +368,7 @@
#endif
-#define NUM_ATTRIBUTES 22
+#define NUM_ATTRIBUTES 26
#define NUM_DEC_ATTRIBUTES (NUM_ATTRIBUTES+12)
static XF86AttributeRec Attributes[NUM_DEC_ATTRIBUTES+1] =
@@ -379,6 +380,10 @@
{XvSettable , 0, 1, "XV_SET_DEFAULTS"},
{XvSettable | XvGettable, 0, 1, "XV_AUTOPAINT_COLORKEY"},
{XvSettable | XvGettable, 0, ~0,"XV_COLORKEY"},
+ {XvSettable | XvGettable, 0, ~0,"XV_OV0_FLAG_CNTL"},
+ {XvSettable | XvGettable, 0, ~0,"XV_OV0_GAMMA_000_00F"},
+ {XvSettable | XvGettable, 0, ~0,"XV_OV0_GAMMA_010_01F"},
+ {XvSettable | XvGettable, 0, ~0,"XV_OV0_GAMMA_020_03F"},
{XvSettable | XvGettable, 0, 1, "XV_DOUBLE_BUFFER"},
{XvSettable | XvGettable, 0, 255, "XV_OVERLAY_ALPHA"},
{XvSettable | XvGettable, 0, 255, "XV_GRAPHICS_ALPHA"},
@@ -679,9 +684,9 @@
static GAMMA_CURVE_R200 gamma_curve_r200[8] =
{
/* Gamma 1.0 */
- {0x00000040, 0x00000000,
- 0x00000040, 0x00000020,
- 0x00000080, 0x00000040,
+ {0x00000100, 0x00000000,
+ 0x00000100, 0x00000020,
+ 0x00000100, 0x00000040,
0x00000100, 0x00000080,
0x00000100, 0x00000100,
0x00000100, 0x00000100,
@@ -840,8 +845,40 @@
0.9135}
};
+
+static double gammafn(double x, double g)
+{
+ return pow(x, 1.0/g);
+}
+
+static CARD32 calc_gamma_r300(CARD32 gamma, int idx)
+{
+ double y0, y1, y2, dy, range;
+ double g;
+ int offsets[] = {0x000, 0x010, 0x020, 0x040, 0x080, 0x0c0,
+ 0x100, 0x140, 0x180, 0x1c0,
+ 0x200, 0x240, 0x280, 0x2c0,
+ 0x300, 0x340, 0x380, 0x3c0,
+ 0x400};
+ CARD32 offset, slope;
+
+ idx = ClipValue(idx, 0, sizeof(offsets)/sizeof(int)-1);
+ g = (double)gamma / 1000.0;
+
+ range = offsets[idx+1] - offsets[idx];
+ y0 = gammafn((double)offsets[idx<4?idx:idx&~1]/(double)0x400, g);
+ y1 = gammafn((double)offsets[idx]/(double)0x400, g);
+ y2 = gammafn((double)offsets[idx+1]/(double)0x400, g);
+ dy = y2-y1;
+
+ offset = y0*0x800+0.5;
+ slope = dy*0x40000/range+0.5;
+
+ return offset | (slope << 0x10);
+}
+
static void
-RADEONSetOverlayGamma(ScrnInfoPtr pScrn, CARD32 gamma)
+RADEONSetOverlayGamma(ScrnInfoPtr pScrn, CARD32 gamma, CARD32 user_gamma)
{
RADEONInfoPtr info = RADEONPTR(pScrn);
unsigned char *RADEONMMIO = info->MMIO;
@@ -850,64 +887,28 @@
/* Set gamma */
RADEONWaitForIdleMMIO(pScrn);
ov0_scale_cntl = INREG(RADEON_OV0_SCALE_CNTL) &
~RADEON_SCALER_GAMMA_SEL_MASK;
- OUTREG(RADEON_OV0_SCALE_CNTL, ov0_scale_cntl | (gamma << 0x00000005));
+ OUTREG(RADEON_OV0_SCALE_CNTL, ov0_scale_cntl);
/* Load gamma curve adjustments */
if (info->ChipFamily >= CHIP_FAMILY_R200) {
- OUTREG(RADEON_OV0_GAMMA_000_00F,
- (gamma_curve_r200[gamma].GAMMA_0_F_OFFSET << 0x00000000) |
- (gamma_curve_r200[gamma].GAMMA_0_F_SLOPE << 0x00000010));
- OUTREG(RADEON_OV0_GAMMA_010_01F,
- (gamma_curve_r200[gamma].GAMMA_10_1F_OFFSET << 0x00000000) |
- (gamma_curve_r200[gamma].GAMMA_10_1F_SLOPE << 0x00000010));
- OUTREG(RADEON_OV0_GAMMA_020_03F,
- (gamma_curve_r200[gamma].GAMMA_20_3F_OFFSET << 0x00000000) |
- (gamma_curve_r200[gamma].GAMMA_20_3F_SLOPE << 0x00000010));
- OUTREG(RADEON_OV0_GAMMA_040_07F,
- (gamma_curve_r200[gamma].GAMMA_40_7F_OFFSET << 0x00000000) |
- (gamma_curve_r200[gamma].GAMMA_40_7F_SLOPE << 0x00000010));
- OUTREG(RADEON_OV0_GAMMA_080_0BF,
- (gamma_curve_r200[gamma].GAMMA_80_BF_OFFSET << 0x00000000) |
- (gamma_curve_r200[gamma].GAMMA_80_BF_SLOPE << 0x00000010));
- OUTREG(RADEON_OV0_GAMMA_0C0_0FF,
- (gamma_curve_r200[gamma].GAMMA_C0_FF_OFFSET << 0x00000000) |
- (gamma_curve_r200[gamma].GAMMA_C0_FF_SLOPE << 0x00000010));
- OUTREG(RADEON_OV0_GAMMA_100_13F,
- (gamma_curve_r200[gamma].GAMMA_100_13F_OFFSET << 0x00000000) |
- (gamma_curve_r200[gamma].GAMMA_100_13F_SLOPE << 0x00000010));
- OUTREG(RADEON_OV0_GAMMA_140_17F,
- (gamma_curve_r200[gamma].GAMMA_140_17F_OFFSET << 0x00000000) |
- (gamma_curve_r200[gamma].GAMMA_140_17F_SLOPE << 0x00000010));
- OUTREG(RADEON_OV0_GAMMA_180_1BF,
- (gamma_curve_r200[gamma].GAMMA_180_1BF_OFFSET << 0x00000000) |
- (gamma_curve_r200[gamma].GAMMA_180_1BF_SLOPE << 0x00000010));
- OUTREG(RADEON_OV0_GAMMA_1C0_1FF,
- (gamma_curve_r200[gamma].GAMMA_1C0_1FF_OFFSET << 0x00000000) |
- (gamma_curve_r200[gamma].GAMMA_1C0_1FF_SLOPE << 0x00000010));
- OUTREG(RADEON_OV0_GAMMA_200_23F,
- (gamma_curve_r200[gamma].GAMMA_200_23F_OFFSET << 0x00000000) |
- (gamma_curve_r200[gamma].GAMMA_200_23F_SLOPE << 0x00000010));
- OUTREG(RADEON_OV0_GAMMA_240_27F,
- (gamma_curve_r200[gamma].GAMMA_240_27F_OFFSET << 0x00000000) |
- (gamma_curve_r200[gamma].GAMMA_240_27F_SLOPE << 0x00000010));
- OUTREG(RADEON_OV0_GAMMA_280_2BF,
- (gamma_curve_r200[gamma].GAMMA_280_2BF_OFFSET << 0x00000000) |
- (gamma_curve_r200[gamma].GAMMA_280_2BF_SLOPE << 0x00000010));
- OUTREG(RADEON_OV0_GAMMA_2C0_2FF,
- (gamma_curve_r200[gamma].GAMMA_2C0_2FF_OFFSET << 0x00000000) |
- (gamma_curve_r200[gamma].GAMMA_2C0_2FF_SLOPE << 0x00000010));
- OUTREG(RADEON_OV0_GAMMA_300_33F,
- (gamma_curve_r200[gamma].GAMMA_300_33F_OFFSET << 0x00000000) |
- (gamma_curve_r200[gamma].GAMMA_300_33F_SLOPE << 0x00000010));
- OUTREG(RADEON_OV0_GAMMA_340_37F,
- (gamma_curve_r200[gamma].GAMMA_340_37F_OFFSET << 0x00000000) |
- (gamma_curve_r200[gamma].GAMMA_340_37F_SLOPE << 0x00000010));
- OUTREG(RADEON_OV0_GAMMA_380_3BF,
- (gamma_curve_r200[gamma].GAMMA_380_3BF_OFFSET << 0x00000000) |
- (gamma_curve_r200[gamma].GAMMA_380_3BF_SLOPE << 0x00000010));
- OUTREG(RADEON_OV0_GAMMA_3C0_3FF,
- (gamma_curve_r200[gamma].GAMMA_3C0_3FF_OFFSET << 0x00000000) |
- (gamma_curve_r200[gamma].GAMMA_3C0_3FF_SLOPE << 0x00000010));
+ OUTREG(RADEON_OV0_GAMMA_000_00F, calc_gamma_r300(user_gamma, 0));
+ OUTREG(RADEON_OV0_GAMMA_010_01F, calc_gamma_r300(user_gamma, 1));
+ OUTREG(RADEON_OV0_GAMMA_020_03F, calc_gamma_r300(user_gamma, 2));
+ OUTREG(RADEON_OV0_GAMMA_040_07F, calc_gamma_r300(user_gamma, 3));
+ OUTREG(RADEON_OV0_GAMMA_080_0BF, calc_gamma_r300(user_gamma, 4));
+ OUTREG(RADEON_OV0_GAMMA_0C0_0FF, calc_gamma_r300(user_gamma, 5));
+ OUTREG(RADEON_OV0_GAMMA_100_13F, calc_gamma_r300(user_gamma, 6));
+ OUTREG(RADEON_OV0_GAMMA_140_17F, calc_gamma_r300(user_gamma, 7));
+ OUTREG(RADEON_OV0_GAMMA_180_1BF, calc_gamma_r300(user_gamma, 8));
+ OUTREG(RADEON_OV0_GAMMA_1C0_1FF, calc_gamma_r300(user_gamma, 9));
+ OUTREG(RADEON_OV0_GAMMA_200_23F, calc_gamma_r300(user_gamma, 10));
+ OUTREG(RADEON_OV0_GAMMA_240_27F, calc_gamma_r300(user_gamma, 11));
+ OUTREG(RADEON_OV0_GAMMA_280_2BF, calc_gamma_r300(user_gamma, 12));
+ OUTREG(RADEON_OV0_GAMMA_2C0_2FF, calc_gamma_r300(user_gamma, 13));
+ OUTREG(RADEON_OV0_GAMMA_300_33F, calc_gamma_r300(user_gamma, 14));
+ OUTREG(RADEON_OV0_GAMMA_340_37F, calc_gamma_r300(user_gamma, 15));
+ OUTREG(RADEON_OV0_GAMMA_380_3BF, calc_gamma_r300(user_gamma, 16));
+ OUTREG(RADEON_OV0_GAMMA_3C0_3FF, calc_gamma_r300(user_gamma, 17));
} else {
OUTREG(RADEON_OV0_GAMMA_000_00F,
(gamma_curve_r100[gamma].GAMMA_0_F_OFFSET << 0x00000000) |
@@ -1080,7 +1081,7 @@
}
/* set gamma */
- RADEONSetOverlayGamma(pScrn, gamma);
+ RADEONSetOverlayGamma(pScrn, gamma, user_gamma);
/* color transforms */
OUTREG(RADEON_OV0_LIN_TRANS_A, dwOvRCb | dwOvLuma);
@@ -1217,6 +1218,10 @@
xvSetDefaults = MAKE_ATOM("XV_SET_DEFAULTS");
xvCRTC = MAKE_ATOM("XV_CRTC");
+ xvOV0FlagControl = MAKE_ATOM("XV_OV0_FLAG_CNTL");
+ xvOV0Gamma00000f = MAKE_ATOM("XV_OV0_GAMMA_000_00F");
+ xvOV0Gamma01001f = MAKE_ATOM("XV_OV0_GAMMA_010_01F");
+ xvOV0Gamma02003f = MAKE_ATOM("XV_OV0_GAMMA_020_03F");
xvOvAlpha = MAKE_ATOM("XV_OVERLAY_ALPHA");
xvGrAlpha = MAKE_ATOM("XV_GRAPHICS_ALPHA");
xvAlphaMode = MAKE_ATOM("XV_ALPHA_MODE");
@@ -1285,7 +1290,7 @@
* segments are programmable in the older Radeons.
*/
- RADEONSetOverlayGamma(pScrn, 0); /* gamma = 1.0 */
+ RADEONSetOverlayGamma(pScrn, 0, 1000); /* gamma = 1.0 */
if(pPriv->VIP!=NULL){
RADEONVIP_reset(pScrn,pPriv);
@@ -1868,6 +1873,22 @@
if(pPriv->i2c != NULL) RADEON_board_setmisc(pPriv);
if(pPriv->uda1380 != NULL)
xf86_uda1380_setvolume(pPriv->uda1380, value);
}
+ else if(attribute == xvOV0FlagControl)
+ {
+ OUTREG(RADEON_OV0_FLAG_CNTL, value);
+ }
+ else if(attribute == xvOV0Gamma00000f)
+ {
+ OUTREG(RADEON_OV0_GAMMA_000_00F, value);
+ }
+ else if(attribute == xvOV0Gamma01001f)
+ {
+ OUTREG(RADEON_OV0_GAMMA_010_01F, value);
+ }
+ else if(attribute == xvOV0Gamma02003f)
+ {
+ OUTREG(RADEON_OV0_GAMMA_020_03F, value);
+ }
else if(attribute == xvOverlayDeinterlacingMethod)
{
if(value<0)value = 0;
@@ -1944,6 +1965,7 @@
pointer data)
{
RADEONInfoPtr info = RADEONPTR(pScrn);
+ unsigned char *RADEONMMIO = info->MMIO;
RADEONPortPrivPtr pPriv = (RADEONPortPrivPtr)data;
if (info->accelOn) RADEON_SYNC(info, pScrn);
@@ -2025,6 +2047,14 @@
*value = pPriv->instance_id;
else if(attribute == xvAdjustment)
*value = pPriv->adjustment;
+ else if(attribute == xvOV0FlagControl)
+ *value = INREG(RADEON_OV0_FLAG_CNTL);
+ else if(attribute == xvOV0Gamma00000f)
+ *value = INREG(RADEON_OV0_GAMMA_000_00F);
+ else if(attribute == xvOV0Gamma01001f)
+ *value = INREG(RADEON_OV0_GAMMA_010_01F);
+ else if(attribute == xvOV0Gamma02003f)
+ *value = INREG(RADEON_OV0_GAMMA_020_03F);
else
return BadMatch;
--
Configure bugmail: http://bugs.freedesktop.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the assignee for the bug.
More information about the xorg-driver-ati
mailing list