These two patches should accomplish the following:

- Usage of Gamma in xorg.conf will be associated with an output and set on the initial crtc. (This should work as good as possible for clone modes, eg a non-1.0 gamma will not be overwritten with a standard value)
- Gamma is stored from preinit and between server generations.
- The old colourmap system will be disabled if gamma hook is available.
- xrandr can now set gamma.

My main question is, are there any xserver ABI's to bump due to the changes to the xf86CrtcRec struct?

Maarten.



diff --git a/hw/xfree86/common/Makefile.am b/hw/xfree86/common/Makefile.am
index 01b9cf3..b562e66 100644
--- a/hw/xfree86/common/Makefile.am
+++ b/hw/xfree86/common/Makefile.am
@@ -42,7 +42,7 @@ INCLUDES = $(XORG_INCS) -I$(srcdir)/../ddc -I$(srcdir)/../i2c 
\
           -I$(srcdir)/../loader -I$(srcdir)/../rac -I$(srcdir)/../parser \
            -I$(srcdir)/../vbe -I$(srcdir)/../int10 \
           -I$(srcdir)/../vgahw -I$(srcdir)/../dixmods/extmod \
-          -I$(srcdir)/../modes
+          -I$(srcdir)/../modes -I$(srcdir)/../ramdac
 
 sdk_HEADERS = compiler.h fourcc.h xf86.h xf86Module.h xf86Opt.h \
               xf86PciInfo.h xf86Priv.h xf86Privstr.h xf86Resources.h \
diff --git a/hw/xfree86/common/xf86Helper.c b/hw/xfree86/common/xf86Helper.c
index 0a66f80..78df060 100644
--- a/hw/xfree86/common/xf86Helper.c
+++ b/hw/xfree86/common/xf86Helper.c
@@ -60,6 +60,7 @@
 #include "mivalidate.h"
 #include "xf86RAC.h"
 #include "xf86Bus.h"
+#include "xf86Crtc.h"
 
 /* For xf86GetClocks */
 #if defined(CSRG_BASED) || defined(__GNU__)
@@ -918,6 +919,11 @@ Bool
 xf86SetGamma(ScrnInfoPtr scrp, Gamma gamma)
 {
     MessageType from = X_DEFAULT;
+    /* Pretend we succeeded if we support better a gamma system.
+     * This avoids a confusing message.
+     */
+    if (xf86_crtc_supports_gamma(scrp))
+       return TRUE;
 #if 0
     xf86MonPtr DDC = (xf86MonPtr)(scrp->monitor->DDC);
 #endif
diff --git a/hw/xfree86/common/xf86cmap.c b/hw/xfree86/common/xf86cmap.c
index bb1aff1..be50a5c 100644
--- a/hw/xfree86/common/xf86cmap.c
+++ b/hw/xfree86/common/xf86cmap.c
@@ -49,6 +49,7 @@
 #include "xf86_OSproc.h"
 #include "xf86str.h"
 #include "micmap.h"
+#include "xf86Crtc.h"
 
 #ifdef XFreeXDGA
 #define _XF86DGA_SERVER_
@@ -141,6 +142,10 @@ Bool xf86HandleColormaps(
     int *indices; 
     int elements;
 
+    /* If we support a better colormap system, then pretend we succeeded. */
+    if (xf86_crtc_supports_gamma(pScrn))
+       return TRUE;
+
     if(!maxColors || !sigRGBbits || !loadPalette)
        return FALSE;
 
diff --git a/hw/xfree86/modes/xf86Crtc.c b/hw/xfree86/modes/xf86Crtc.c
index ef2ecb7..7a3bb89 100644
--- a/hw/xfree86/modes/xf86Crtc.c
+++ b/hw/xfree86/modes/xf86Crtc.c
@@ -117,6 +117,12 @@ xf86CrtcCreate (ScrnInfoPtr                scrn,
     crtc->desiredTransformPresent = FALSE;
     memset (&crtc->bounds, '\0', sizeof (crtc->bounds));
 
+    /* Preallocate gamma at a sensible size. */
+    crtc->gamma_size = 256;
+    crtc->gamma_red = malloc(3 * crtc->gamma_size * sizeof (CARD16));
+    crtc->gamma_green = crtc->gamma_red + crtc->gamma_size;
+    crtc->gamma_blue = crtc->gamma_green + crtc->gamma_size;
+
     if (xf86_config->crtc)
        crtcs = xrealloc (xf86_config->crtc,
                          (xf86_config->num_crtc + 1) * sizeof (xf86CrtcPtr));
@@ -150,6 +156,7 @@ xf86CrtcDestroy (xf86CrtcPtr crtc)
        }
     if (crtc->params)
        xfree (crtc->params);
+    free(crtc->gamma_red);
     xfree (crtc);
 }
 
@@ -2207,6 +2214,97 @@ xf86TargetUserpref(ScrnInfoPtr scrn, xf86CrtcConfigPtr 
config,
     return FALSE;
 }
 
+static Bool
+xf86CrtcSetInitialGamma(xf86CrtcPtr crtc, float gamma_red, float gamma_green,
+        float gamma_blue)
+{
+    int i, size = 256;
+    CARD16 *red, *green, *blue;
+
+    red = malloc(3 * size * sizeof(CARD16));
+    green = red + size;
+    blue = green + size;
+
+     /* Only cause warning if user wanted gamma to be set. */
+    if (!crtc->funcs->gamma_set && (gamma_red != 1.0 || gamma_green != 1.0 || 
gamma_blue != 1.0))
+        return FALSE;
+    else if (!crtc->funcs->gamma_set)
+        return TRUE;
+
+    /* At this early stage none of the randr-interface stuff is up.
+     * So take the default gamma size for lack of something better.
+     */
+    for (i = 0; i < size; i++) {
+        /* Code partially borrowed from ComputeGamma(). */
+        if (gamma_red == 1.0)
+            red[i] = i << 8;
+        else
+            red[i] = (CARD16)((pow((double)i/(double)size,
+                        gamma_red) * (double)size + 0.5)*256);
+
+        if (gamma_green == 1.0)
+            green[i] = i << 8;
+        else
+            green[i] = (CARD16)((pow((double)i/(double)size,
+                        gamma_green) * (double)size + 0.5)*256);
+
+        if (gamma_blue == 1.0)
+            blue[i] = i << 8;
+        else
+            blue[i] = (CARD16)((pow((double)i/(double)size,
+                        gamma_blue) * (double)size + 0.5)*256);
+    }
+
+    /* Default size is 256, so anything else is failure. */
+    if (size != crtc->gamma_size)
+        return FALSE;
+
+    crtc->gamma_size = size;
+    memcpy (crtc->gamma_red, red, crtc->gamma_size * sizeof (CARD16));
+    memcpy (crtc->gamma_green, green, crtc->gamma_size * sizeof (CARD16));
+    memcpy (crtc->gamma_blue, blue, crtc->gamma_size * sizeof (CARD16));
+
+    /* Use copied values, the perfect way to test if all went well. */
+    crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
+                                            crtc->gamma_blue, 
crtc->gamma_size);
+
+    free(red);
+
+    return TRUE;
+}
+
+static Bool
+xf86OutputSetInitialGamma(xf86OutputPtr output)
+{
+    XF86ConfMonitorPtr mon = output->conf_monitor;
+    float gamma_red = 1.0, gamma_green = 1.0, gamma_blue = 1.0;
+    
+    if (!mon)
+        return TRUE;
+
+    if (!output->crtc)
+        return FALSE;
+
+    /* Get configured values, where they exist. */
+    if (mon->mon_gamma_red >= GAMMA_MIN &&
+        mon->mon_gamma_red <= GAMMA_MAX)
+            gamma_red = mon->mon_gamma_red;
+
+    if (mon->mon_gamma_green >= GAMMA_MIN &&
+        mon->mon_gamma_green <= GAMMA_MAX)
+            gamma_green = mon->mon_gamma_green;
+
+    if (mon->mon_gamma_blue >= GAMMA_MIN &&
+        mon->mon_gamma_blue <= GAMMA_MAX)
+            gamma_blue = mon->mon_gamma_blue;
+
+    /* This avoids setting gamma 1.0 in case another cloned output in has a 
specific gamma. */
+    if (gamma_red != 1.0 || gamma_green != 1.0 || gamma_blue != 1.0) {
+       xf86DrvMsg(output->scrn->scrnIndex, X_INFO, "Output %s wants gamma 
correction (%.1f, %.1f, %.1f)\n", output->name, gamma_red, gamma_green, 
gamma_blue);
+       return xf86CrtcSetInitialGamma(output->crtc, gamma_red, gamma_green, 
gamma_blue);
+    }else
+       return TRUE;
+}
 
 /**
  * Construct default screen configuration
@@ -2317,8 +2415,11 @@ xf86InitialConfiguration (ScrnInfoPtr scrn, Bool canGrow)
 
        crtc->enabled = FALSE;
        memset (&crtc->desiredMode, '\0', sizeof (crtc->desiredMode));
+       /* Set default gamma for all crtc's. */
+       /* This is done to avoid problems later on with cloned outputs. */
+       xf86CrtcSetInitialGamma(crtc, 1.0, 1.0, 1.0);
     }
-    
+
     /*
      * Set initial configuration
      */
@@ -2342,11 +2443,13 @@ xf86InitialConfiguration (ScrnInfoPtr scrn, Bool 
canGrow)
            memcpy (&crtc->panningTrackingArea, &output->initialTrackingArea, 
sizeof(BoxRec));
            memcpy (crtc->panningBorder,        output->initialBorder,        
4*sizeof(INT16));
            output->crtc = crtc;
+           if (!xf86OutputSetInitialGamma(output))
+               xf86DrvMsg (scrn->scrnIndex, X_WARNING, "Initial gamma 
correction for output %s: failed.\n", output->name);
        } else {
            output->crtc = NULL;
        }
     }
-    
+
     if (scrn->display->virtualX == 0)
     {
        /*
@@ -3029,3 +3132,21 @@ xf86_crtc_notify(ScreenPtr screen)
     if (config->xf86_crtc_notify)
        config->xf86_crtc_notify(screen);
 }
+
+Bool
+xf86_crtc_supports_gamma(ScrnInfoPtr pScrn)
+{
+    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+    xf86CrtcPtr crtc;
+    int c;
+
+    for (c = 0; c < xf86_config->num_crtc; c++) {
+        crtc = xf86_config->crtc[c];
+        if (crtc->funcs->gamma_set)
+            return TRUE;
+        else
+            return FALSE;
+    }
+
+    return FALSE;
+}
diff --git a/hw/xfree86/modes/xf86Crtc.h b/hw/xfree86/modes/xf86Crtc.h
index e44996f..fb9f77d 100644
--- a/hw/xfree86/modes/xf86Crtc.h
+++ b/hw/xfree86/modes/xf86Crtc.h
@@ -337,6 +337,14 @@ struct _xf86Crtc {
     BoxRec          panningTotalArea;
     BoxRec          panningTrackingArea;
     INT16           panningBorder[4];
+
+    /**
+     * Current gamma, especially useful after initial config.
+     */
+    CARD16 *gamma_red;
+    CARD16 *gamma_green;
+    CARD16 *gamma_blue;
+    int gamma_size;
 };
 
 typedef struct _xf86OutputFuncs {
@@ -914,4 +922,12 @@ xf86_crtc_set_panning(ScrnInfoPtr pScrn,
                      BoxPtr      TrackingArea,
                      INT16      *border);
 
+
+/**
+ * Gamma
+ */
+
+Bool
+xf86_crtc_supports_gamma(ScrnInfoPtr pScrn);
+
 #endif /* _XF86CRTC_H_ */
diff --git a/hw/xfree86/modes/xf86RandR12.c b/hw/xfree86/modes/xf86RandR12.c
index d668ab7..8deb64c 100644
--- a/hw/xfree86/modes/xf86RandR12.c
+++ b/hw/xfree86/modes/xf86RandR12.c
@@ -1046,8 +1046,55 @@ xf86RandR12CrtcSetGamma (ScreenPtr    pScreen,
     if (!crtc->scrn->vtSema)
        return TRUE;
 
-    crtc->funcs->gamma_set(crtc, randr_crtc->gammaRed, randr_crtc->gammaGreen,
-                          randr_crtc->gammaBlue, randr_crtc->gammaSize);
+    /* Realloc local gamma if needed. */
+    if (randr_crtc->gammaSize != crtc->gamma_size) {
+        CARD16 *tmp_ptr;
+        tmp_ptr = realloc(crtc->gamma_red, 3 * crtc->gamma_size * sizeof 
(CARD16));
+        if (!tmp_ptr)
+            return FALSE;
+        crtc->gamma_red = tmp_ptr;
+        crtc->gamma_green = crtc->gamma_red + crtc->gamma_size;
+        crtc->gamma_blue = crtc->gamma_green + crtc->gamma_size;
+    }
+
+    crtc->gamma_size = randr_crtc->gammaSize;
+    memcpy (crtc->gamma_red, randr_crtc->gammaRed, crtc->gamma_size * sizeof 
(CARD16));
+    memcpy (crtc->gamma_green, randr_crtc->gammaGreen, crtc->gamma_size * 
sizeof (CARD16));
+    memcpy (crtc->gamma_blue, randr_crtc->gammaBlue, crtc->gamma_size * sizeof 
(CARD16));
+
+    /* Use copied values, the perfect way to test if all went well. */
+    crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
+                                            crtc->gamma_blue, 
crtc->gamma_size);
+
+    return TRUE;
+}
+
+static Bool
+xf86RandR12CrtcGetGamma (ScreenPtr    pScreen,
+                        RRCrtcPtr    randr_crtc)
+{
+    xf86CrtcPtr crtc = randr_crtc->devPrivate;
+
+    if (!crtc->gamma_size)
+        return FALSE;
+
+    if (!crtc->gamma_red || !crtc->gamma_green || !crtc->gamma_blue)
+        return FALSE;
+
+    /* Realloc randr gamma if needed. */
+    if (randr_crtc->gammaSize != crtc->gamma_size) {
+        CARD16 *tmp_ptr;
+        tmp_ptr = realloc(randr_crtc->gammaRed, 3 * crtc->gamma_size * sizeof 
(CARD16));
+        if (!tmp_ptr)
+            return FALSE;
+        randr_crtc->gammaRed = tmp_ptr;
+        randr_crtc->gammaGreen = randr_crtc->gammaRed + crtc->gamma_size;
+        randr_crtc->gammaBlue = randr_crtc->gammaGreen + crtc->gamma_size;
+    }
+    randr_crtc->gammaSize = crtc->gamma_size;
+    memcpy (randr_crtc->gammaRed, crtc->gamma_red, crtc->gamma_size * sizeof 
(CARD16));
+    memcpy (randr_crtc->gammaGreen, crtc->gamma_green, crtc->gamma_size * 
sizeof (CARD16));
+    memcpy (randr_crtc->gammaBlue, crtc->gamma_blue, crtc->gamma_size * sizeof 
(CARD16));
 
     return TRUE;
 }
@@ -1443,6 +1490,7 @@ xf86RandR12Init12 (ScreenPtr pScreen)
     rp->rrScreenSetSize = xf86RandR12ScreenSetSize;
     rp->rrCrtcSet = xf86RandR12CrtcSet;
     rp->rrCrtcSetGamma = xf86RandR12CrtcSetGamma;
+    rp->rrCrtcGetGamma = xf86RandR12CrtcGetGamma;
     rp->rrOutputSetProperty = xf86RandR12OutputSetProperty;
     rp->rrOutputValidateMode = xf86RandR12OutputValidateMode;
 #if RANDR_13_INTERFACE
diff --git a/randr/randrstr.h b/randr/randrstr.h
index b868144..be596d4 100644
--- a/randr/randrstr.h
+++ b/randr/randrstr.h
@@ -173,6 +173,9 @@ typedef Bool (*RRCrtcSetProcPtr) (ScreenPtr         pScreen,
 typedef Bool (*RRCrtcSetGammaProcPtr) (ScreenPtr       pScreen,
                                       RRCrtcPtr        crtc);
 
+typedef Bool (*RRCrtcGetGammaProcPtr) (ScreenPtr       pScreen,
+                                      RRCrtcPtr        crtc);
+
 typedef Bool (*RROutputSetPropertyProcPtr) (ScreenPtr          pScreen,
                                            RROutputPtr         output,
                                            Atom                property,
@@ -245,6 +248,7 @@ typedef struct _rrScrPriv {
     RRScreenSetSizeProcPtr  rrScreenSetSize;
     RRCrtcSetProcPtr       rrCrtcSet;
     RRCrtcSetGammaProcPtr   rrCrtcSetGamma;
+    RRCrtcGetGammaProcPtr   rrCrtcGetGamma;
     RROutputSetPropertyProcPtr rrOutputSetProperty;
     RROutputValidateModeProcPtr        rrOutputValidateMode;
     RRModeDestroyProcPtr       rrModeDestroy;
@@ -586,6 +590,14 @@ RRCrtcGammaSet (RRCrtcPtr   crtc,
                CARD16      *blue);
 
 /*
+ * Request current gamma back from the DDX (if possible).
+ * This includes gamma size.
+ */
+ 
+extern _X_EXPORT Bool
+RRCrtcGammaGet(RRCrtcPtr crtc);
+
+/*
  * Notify the extension that the Crtc gamma has been changed
  * The driver calls this whenever it has changed the gamma values
  * in the RRCrtcRec
diff --git a/randr/rrcrtc.c b/randr/rrcrtc.c
index b504b0c..d8aa37b 100644
--- a/randr/rrcrtc.c
+++ b/randr/rrcrtc.c
@@ -480,6 +480,29 @@ RRCrtcGammaSet (RRCrtcPtr   crtc,
 }
 
 /*
+ * Request current gamma back from the DDX (if possible).
+ * This includes gamma size.
+ */
+Bool
+RRCrtcGammaGet(RRCrtcPtr crtc)
+{
+    Bool ret = TRUE;
+#if RANDR_12_INTERFACE
+    ScreenPtr  pScreen = crtc->pScreen;
+#endif
+
+#if RANDR_12_INTERFACE
+    if (pScreen)
+    {
+        rrScrPriv(pScreen);
+        if (pScrPriv->rrCrtcGetGamma)
+            ret = (*pScrPriv->rrCrtcGetGamma) (pScreen, crtc);
+    }
+#endif
+    return ret;
+}
+
+/*
  * Notify the extension that the Crtc gamma has been changed
  * The driver calls this whenever it has changed the gamma values
  * in the RRCrtcRec
@@ -1141,7 +1164,11 @@ ProcRRGetCrtcGammaSize (ClientPtr client)
     crtc = LookupCrtc (client, stuff->crtc, DixReadAccess);
     if (!crtc)
        return RRErrorBase + BadRRCrtc;
-    
+
+    /* Gamma retrieval failed, any better error? */
+    if (!RRCrtcGammaGet(crtc))
+        return RRErrorBase + BadRRCrtc;
+
     reply.type = X_Reply;
     reply.sequenceNumber = client->sequence;
     reply.length = 0;
@@ -1169,7 +1196,11 @@ ProcRRGetCrtcGamma (ClientPtr client)
     crtc = LookupCrtc (client, stuff->crtc, DixReadAccess);
     if (!crtc)
        return RRErrorBase + BadRRCrtc;
-    
+
+    /* Gamma retrieval failed, any better error? */
+    if (!RRCrtcGammaGet(crtc))
+        return RRErrorBase + BadRRCrtc;
+
     len = crtc->gammaSize * 3 * 2;
     
     if (crtc->gammaSize) {
diff --git a/xrandr.c b/xrandr.c
index ed31f0e..20dfaf5 100644
--- a/xrandr.c
+++ b/xrandr.c
@@ -134,6 +134,7 @@ usage(void)
     fprintf(stderr, "      --off\n");
     fprintf(stderr, "      --crtc <crtc>\n");
     fprintf(stderr, "      --panning 
<w>x<h>[+<x>+<y>[/<track:w>x<h>+<x>+<y>[/<border:l>/<t>/<r>/<b>]]]\n");
+    fprintf(stderr, "      --gamma <r>:<g>:<b>\n");
     fprintf(stderr, "  --newmode <name> <clock MHz>\n");
     fprintf(stderr, "            <hdisp> <hsync-start> <hsync-end> 
<htotal>\n");
     fprintf(stderr, "            <vdisp> <vsync-start> <vsync-end> 
<vtotal>\n");
@@ -235,6 +236,7 @@ typedef enum _changes {
     changes_property = (1 << 8),
     changes_transform = (1 << 9),
     changes_panning = (1 << 10),
+    changes_gamma = (1 << 11),
 } changes_t;
 
 typedef enum _name_kind {
@@ -311,11 +313,17 @@ struct _output {
 
     int                    x, y;
     Rotation       rotation;
-    
+
     XRRPanning      panning;
 
     Bool           automatic;
     transform_t            transform;
+
+    struct {
+       float red;
+       float green;
+       float blue;
+    } gamma;
 };
 
 typedef enum _umode_action {
@@ -1142,6 +1150,66 @@ set_panning (void)
     }
 }
 
+static void
+set_gamma()
+{
+    output_t   *output;
+
+    for (output = outputs; output; output = output->next) {
+       int i, size;
+       crtc_t *crtc;
+       XRRCrtcGamma *gamma;
+
+       if (!(output->changes & changes_gamma))
+           continue;
+
+       if (!output->crtc_info) {
+           fatal("Need crtc to set gamma on.\n");
+           continue;
+       }
+
+       crtc = output->crtc_info;
+
+       size = XRRGetCrtcGammaSize(dpy, crtc->crtc.xid);
+
+       if (!size) {
+           fatal("Gamma size is 0.\n");
+           continue;
+       }
+
+       gamma = XRRAllocGamma(size);
+       if (!gamma) {
+           fatal("Gamma allocation failed.\n");
+           continue;
+       }
+
+       for (i = 0; i < size; i++) {
+           /* Code partially borrowed from ComputeGamma(). */
+           if (output->gamma.red == 1.0)
+               gamma->red[i] = i << 8;
+           else
+               gamma->red[i] = (CARD16)((pow((double)i/(double)size,
+                           output->gamma.red) * (double)size + 0.5)*256);
+
+           if (output->gamma.green == 1.0)
+               gamma->green[i] = i << 8;
+           else
+               gamma->green[i] = (CARD16)((pow((double)i/(double)size,
+                           output->gamma.green) * (double)size + 0.5)*256);
+
+           if (output->gamma.blue == 1.0)
+               gamma->blue[i] = i << 8;
+           else
+               gamma->blue[i] = (CARD16)((pow((double)i/(double)size,
+                           output->gamma.blue) * (double)size + 0.5)*256);
+       }
+
+       XRRSetCrtcGamma(dpy, crtc->crtc.xid, gamma);
+
+       free(gamma);
+    }
+}
+
 static Status
 crtc_disable (crtc_t *crtc)
 {
@@ -2151,6 +2219,16 @@ main (int argc, char **argv)
            output->changes |= changes_panning;
            continue;
        }
+       if (!strcmp ("--gamma", argv[i])) {
+           if (!output) usage();
+           if (++i>=argc) usage ();
+           if (sscanf(argv[i], "%f:%f:%f", &output->gamma.red, 
+                   &output->gamma.green, &output->gamma.blue) != 3)
+               usage ();
+           output->changes |= changes_gamma;
+           setit_1_2 = True;
+           continue;
+       }
        if (!strcmp ("--set", argv[i])) {
            output_prop_t   *prop;
            if (!output) usage();
@@ -2594,7 +2672,12 @@ main (int argc, char **argv)
         * Set panning
         */
        set_panning ();
-       
+
+       /* 
+        * Set gamma on crtc's that belong to the outputs.
+        */
+       set_gamma ();
+
        /*
         * Now apply all of the changes
         */
_______________________________________________
xorg mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/xorg

Reply via email to