[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