From 91f73b79b7ae64e5b846d1efeb470bb61a913720 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Wed, 17 Dec 2008 16:56:26 +0100 Subject: 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. --- hw/xfree86/common/Makefile.am | 2 +- hw/xfree86/common/xf86Helper.c | 6 ++ hw/xfree86/common/xf86cmap.c | 5 ++ hw/xfree86/modes/xf86Crtc.c | 128 ++++++++++++++++++++++++++++++++++++++++- hw/xfree86/modes/xf86Crtc.h | 16 ++++++ hw/xfree86/modes/xf86RandR12.c | 52 ++++++++++++++++- randr/randrstr.h | 12 ++++ randr/rrcrtc.c | 35 ++++++++++- 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; @@ -585,6 +589,14 @@ RRCrtcGammaSet (RRCrtcPtr crtc, CARD16 *green, 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 diff --git a/randr/rrcrtc.c b/randr/rrcrtc.c index b504b0c9b..d8aa37b9c 100644 --- a/randr/rrcrtc.c +++ b/randr/rrcrtc.c @@ -479,6 +479,29 @@ RRCrtcGammaSet (RRCrtcPtr crtc, return ret; } +/* + * 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 @@ -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) { -- cgit v1.2.3