summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaarten Maathuis <madman2003@gmail.com>2008-12-17 16:56:26 +0100
committerMaarten Maathuis <madman2003@gmail.com>2008-12-17 17:03:12 +0100
commit91f73b79b7ae64e5b846d1efeb470bb61a913720 (patch)
treebe97d9678e27abb1399bfc98fb927f40cef1f561
parent1556815d34cecb4b4b62d2a4ce813b1435a937ec (diff)
randr: Improve per-crtc gamma support.
- The Gamma values from the monitor section are now used during initial config. - The old colormap system is disabled when gamma set hook is available. - Gamma values are now persistent for the lifetime of the xserver. - This requires no driver changes and should be driver ABI compatible.
-rw-r--r--hw/xfree86/common/Makefile.am2
-rw-r--r--hw/xfree86/common/xf86Helper.c6
-rw-r--r--hw/xfree86/common/xf86cmap.c5
-rw-r--r--hw/xfree86/modes/xf86Crtc.c128
-rw-r--r--hw/xfree86/modes/xf86Crtc.h16
-rw-r--r--hw/xfree86/modes/xf86RandR12.c52
-rw-r--r--randr/randrstr.h12
-rw-r--r--randr/rrcrtc.c35
8 files changed, 249 insertions, 7 deletions
diff --git a/hw/xfree86/common/Makefile.am b/hw/xfree86/common/Makefile.am
index 01b9cf385..b562e6665 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 0a66f8067..78df06013 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 bb1aff1d9..be50a5c6a 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 b4fe3b199..824edfd4a 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 on this crtc 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,14 @@ 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);
}
-
+
+ if (xf86_crtc_supports_gamma(scrn))
+ xf86DrvMsg(scrn->scrnIndex, X_INFO, "Using default gamma of (1.0, 1.0, 1.0) unless otherwise stated.\n");
+
/*
* Set initial configuration
*/
@@ -2342,11 +2446,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 +3135,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 e44996fba..fb9f77df0 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 d668ab78e..8deb64cdf 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 b868144d5..be596d4e8 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 b504b0c9b..d8aa37b9c 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) {