diff options
author | Aaron Plattner <aplattner@nvidia.com> | 2008-02-12 21:05:03 -0800 |
---|---|---|
committer | Aaron Plattner <aplattner@nvidia.com> | 2008-02-12 21:05:03 -0800 |
commit | ff6454119839f5d439c1ca8eeefb5a9ed55fa579 (patch) | |
tree | f252b339ca7a436594b025c9a73092218809533f /src/libXNVCtrlAttributes/NvCtrlAttributesVidMode.c |
1.0-61061.0-6106
Diffstat (limited to 'src/libXNVCtrlAttributes/NvCtrlAttributesVidMode.c')
-rw-r--r-- | src/libXNVCtrlAttributes/NvCtrlAttributesVidMode.c | 427 |
1 files changed, 427 insertions, 0 deletions
diff --git a/src/libXNVCtrlAttributes/NvCtrlAttributesVidMode.c b/src/libXNVCtrlAttributes/NvCtrlAttributesVidMode.c new file mode 100644 index 0000000..8876e14 --- /dev/null +++ b/src/libXNVCtrlAttributes/NvCtrlAttributesVidMode.c @@ -0,0 +1,427 @@ +/* + * nvidia-settings: A tool for configuring the NVIDIA X driver on Unix + * and Linux systems. + * + * Copyright (C) 2004 NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of Version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Version 2 + * of the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307, USA + * + */ + +#include "NvCtrlAttributes.h" +#include "NvCtrlAttributesPrivate.h" + +#include "msg.h" + +#include <X11/extensions/xf86vmode.h> + +#include <stdlib.h> +#include <math.h> + +static unsigned short computeVal(NvCtrlAttributePrivateHandle *, + int, float, float, float); + +#define RED RED_CHANNEL_INDEX +#define GREEN GREEN_CHANNEL_INDEX +#define BLUE BLUE_CHANNEL_INDEX + + +#if defined(X_XF86VidModeGetGammaRampSize) + +/* + * XXX The XF86VidMode extension can block remote clients. + * Unfortunately, there doesn't seem to be a good way to determine if + * we're blocked or not. So, we temporarily plug in an error handler, + * and watch for the XF86VidModeClientNotLocal error code, set a flag + * indicating that we should not use the XF86VidMode extension, and + * then restore the previous error handler. Yuck. + * + * XXX Different versions of XFree86 trigger errors on different + * protocol; older versions trigger an error on + * XF86VidModeGetGammaRampSize(), but newer versions appear to only + * error on XF86VidModeSetGammaRamp(). + */ + +static Bool vidModeBlocked = False; +static int vidModeErrorBase = 0; +static int (*prev_error_handler)(Display *, XErrorEvent *) = NULL; + +static int vidModeErrorHandler(Display *dpy, XErrorEvent *err) +{ + if (err->error_code == (XF86VidModeClientNotLocal + vidModeErrorBase)) { + vidModeBlocked = True; + } else { + if (prev_error_handler) prev_error_handler(dpy, err); + } + + return 1; +} + +#endif /* X_XF86VidModeGetGammaRampSize */ + + + + +NvCtrlVidModeAttributes * +NvCtrlInitVidModeAttributes(NvCtrlAttributePrivateHandle *h) +{ + NvCtrlVidModeAttributes *vm = NULL; + int ret, event, ver, rev, i; + +#if defined(X_XF86VidModeGetGammaRampSize) + + ret = XF86VidModeQueryExtension(h->dpy, &event, &vidModeErrorBase); + if (ret != True) goto failed; + + ret = XF86VidModeQueryVersion(h->dpy, &ver, &rev); + if (ret != True) goto failed; + + if (ver < VM_MINMAJOR || (ver == VM_MINMAJOR && rev < VM_MINMINOR)) { + nv_warning_msg("The version of the XF86VidMode extension present " + "on this display (%d.%d) does not support updating " + "gamma ramps. If you'd like to be able to adjust " + "gamma ramps, please update your X server such that " + "the version of the XF86VidMode extension is %d.%d " + "or higher.", rev, ver, VM_MINMAJOR, VM_MINMINOR); + goto failed; + } + + vm = (NvCtrlVidModeAttributes *) malloc(sizeof(NvCtrlVidModeAttributes)); + + /* + * XXX setup an error handler to catch any errors caused by the + * VidMode extension blocking remote clients; we'll restore the + * original error handler below + */ + + prev_error_handler = XSetErrorHandler(vidModeErrorHandler); + + ret = XF86VidModeGetGammaRampSize(h->dpy, h->screen, &vm->n); + + /* check if XF86VidModeGetGammaRampSize was blocked */ + + if (vidModeBlocked) { + goto blocked; + } + + if (ret != True) goto failed; + + vm->lut[RED] = (unsigned short *) malloc(sizeof(unsigned short) * vm->n); + vm->lut[GREEN] = (unsigned short *) malloc(sizeof(unsigned short) * vm->n); + vm->lut[BLUE] = (unsigned short *) malloc(sizeof(unsigned short) * vm->n); + + ret = XF86VidModeGetGammaRamp(h->dpy, h->screen, vm->n, vm->lut[RED], + vm->lut[GREEN], vm->lut[BLUE]); + + /* check if XF86VidModeGetGammaRamp was blocked */ + + if (vidModeBlocked) { + goto blocked; + } + + if (ret != True) goto failed; + + /* + * XXX Currently, XF86VidModeSetGammaRamp() is the only other + * XF86VidMode protocol we send, and depending on the XFree86 + * version, it may induce an X error for remote clients. So, try + * sending it here to see if we get an error (yes, this is the + * data we just retrieved above from XF86VidModeGetGammaRamp). + * It's terrible that we have to do this. + */ + + ret = XF86VidModeSetGammaRamp(h->dpy, h->screen, vm->n, + vm->lut[RED], + vm->lut[GREEN], + vm->lut[BLUE]); + /* + * sync the protocol stream to make sure we process any X error + * before continuing + */ + + XSync(h->dpy, False); + + /* check if XF86VidModeSetGammaRamp was blocked */ + + if (vidModeBlocked) { + goto blocked; + } + + /* finally, restore the original error handler */ + + XSetErrorHandler(prev_error_handler); + + /* + * XXX can we initialize this to anything based on the current + * ramps? + */ + + for (i = RED; i <= BLUE; i++) { + vm->brightness[i] = BRIGHTNESS_DEFAULT; + vm->contrast[i] = CONTRAST_DEFAULT; + vm->gamma[i] = GAMMA_DEFAULT; + } + + /* take log2 of vm->n to find the sigbits */ + + for (i = 0; ((vm->n >> i) > 0); i++); + vm->sigbits = i - 1; + + return (vm); + +#else + +#warning Old xf86vmode.h; dynamic gamma ramp support will not be compiled. + +#endif + + blocked: + + nv_warning_msg("The VidMode extension is blocked for remote " + "clients. To allow remote VidMode clients, the " + "XF86Config option \"AllowNonLocalXvidtune\" must be " + "set in the ServerFlags section of the XF86Config " + "file."); + + /* fall through */ + + failed: + if (vm) free(vm); + + /* restore the original error handler, if we overrode it */ + + if (prev_error_handler) { + XSetErrorHandler(prev_error_handler); + prev_error_handler = NULL; + } + + return NULL; + +} /* NvCtrlInitVidModeAttributes() */ + + +ReturnStatus NvCtrlGetColorAttributes(NvCtrlAttributeHandle *handle, + float contrast[3], + float brightness[3], + float gamma[3]) +{ + int i; + NvCtrlAttributePrivateHandle *h; + + h = (NvCtrlAttributePrivateHandle *) handle; + + if (!h->vm) return NvCtrlMissingExtension; + + for (i = RED; i <= BLUE; i++) { + contrast[i] = h->vm->contrast[i]; + brightness[i] = h->vm->brightness[i]; + gamma[i] = h->vm->gamma[i]; + } + + return NvCtrlSuccess; + +} /* NvCtrlGetColorAttributes() */ + + + + + +/* + * NvCtrlSetColorAttributes() - update the color attributes specified + * by bitmask, recompute the LUT, and send the LUT to the X server. + * + * The bitmask parameter is a bitmask of which channels (RED_CHANNEL, + * GREEN_CHANNEL, and BLUE_CHANNEL) and which values (CONTRAST_VALUE, + * BRIGHTNESS_VALUE, GAMMA_VALUE) should be updated. + * + * XXX future optimization: if each channel has the same c/b/g values, + * don't need to compute the ramp separately per channel. + * + * XXX future optimization: if the input is the same as what we + * already have, we don't actually need to recompute the ramp and send + * it to the X server. + */ + +ReturnStatus NvCtrlSetColorAttributes(NvCtrlAttributeHandle *handle, + float c[3], + float b[3], + float g[3], + unsigned int bitmask) +{ + int i, ch; + Bool ret; + +#if defined(X_XF86VidModeGetGammaRampSize) + + NvCtrlAttributePrivateHandle *h; + + h = (NvCtrlAttributePrivateHandle *) handle; + + if (!h || !h->dpy) return NvCtrlBadHandle; + if (!h->vm) return NvCtrlMissingExtension; + + /* clamp input, but only the input specified in the bitmask */ + + for (ch = RED; ch <= BLUE; ch++) { + if (bitmask & (1 << ch)) { + if (bitmask & CONTRAST_VALUE) { + if (c[ch] > CONTRAST_MAX) c[ch] = CONTRAST_MAX; + if (c[ch] < CONTRAST_MIN) c[ch] = CONTRAST_MIN; + } + if (bitmask & BRIGHTNESS_VALUE) { + if (b[ch] > BRIGHTNESS_MAX) b[ch] = BRIGHTNESS_MAX; + if (b[ch] < BRIGHTNESS_MIN) b[ch] = BRIGHTNESS_MIN; + } + if (bitmask & GAMMA_VALUE) { + if (g[ch] > GAMMA_MAX) g[ch] = GAMMA_MAX; + if (g[ch] < GAMMA_MIN) g[ch] = GAMMA_MIN; + } + } + } + + /* assign specified values */ + + if (bitmask & CONTRAST_VALUE) { + if (bitmask & RED_CHANNEL) h->vm->contrast[RED] = c[RED]; + if (bitmask & GREEN_CHANNEL) h->vm->contrast[GREEN] = c[GREEN]; + if (bitmask & BLUE_CHANNEL) h->vm->contrast[BLUE] = c[BLUE]; + } + + if (bitmask & BRIGHTNESS_VALUE) { + if (bitmask & RED_CHANNEL) h->vm->brightness[RED] = b[RED]; + if (bitmask & GREEN_CHANNEL) h->vm->brightness[GREEN] = b[GREEN]; + if (bitmask & BLUE_CHANNEL) h->vm->brightness[BLUE] = b[BLUE]; + } + + if (bitmask & GAMMA_VALUE) { + if (bitmask & RED_CHANNEL) h->vm->gamma[RED] = g[RED]; + if (bitmask & GREEN_CHANNEL) h->vm->gamma[GREEN] = g[GREEN]; + if (bitmask & BLUE_CHANNEL) h->vm->gamma[BLUE] = g[BLUE]; + } + + for (ch = RED; ch <= BLUE; ch++) { + if ( !(bitmask & (1 << ch))) continue; /* don't update this channel */ + for (i = 0; i < h->vm->n; i++) { + h->vm->lut[ch][i] = computeVal(h, i, h->vm->contrast[ch], + h->vm->brightness[ch], + h->vm->gamma[ch]); + } + } + + ret = XF86VidModeSetGammaRamp(h->dpy, h->screen, h->vm->n, + h->vm->lut[RED], + h->vm->lut[GREEN], + h->vm->lut[BLUE]); + + if (ret != True) return NvCtrlError; + + return NvCtrlSuccess; +#else + return NvCtrlMissingExtension; + +#endif /* X_XF86VidModeGetGammaRampSize */ + +} /* NvCtrlSetColorAttribute() */ + + +ReturnStatus NvCtrlGetColorRamp(NvCtrlAttributeHandle *handle, + unsigned int channel, + unsigned short **lut, + int *n) +{ +#if defined(X_XF86VidModeGetGammaRampSize) + + NvCtrlAttributePrivateHandle *h; + + h = (NvCtrlAttributePrivateHandle *) handle; + + if (!h || !h->dpy) return NvCtrlBadHandle; + if (!h->vm) return NvCtrlMissingExtension; + + *n = h->vm->n; + + switch (channel) { + case RED_CHANNEL: *lut = h->vm->lut[RED]; break; + case GREEN_CHANNEL: *lut = h->vm->lut[GREEN]; break; + case BLUE_CHANNEL: *lut = h->vm->lut[BLUE]; break; + default: return NvCtrlBadArgument; + } + + return NvCtrlSuccess; +#else + return NvCtrlMissingExtension; +#endif +} + + +/* + * computeVal() - compute the LUT entry given its index, and the + * contrast, brightness, and gamma. + */ +static unsigned short computeVal(NvCtrlAttributePrivateHandle *h, + int i, float c, float b, float g) +{ + double j, half, scale; + int shift, val, num; + + num = h->vm->n - 1; + shift = 16 - h->vm->sigbits; + + scale = (double) num / 3.0; /* how much brightness and contrast + affect the value */ + j = (double) i; + + /* contrast */ + + c *= scale; + + if (c > 0.0) { + half = ((double) num / 2.0) - 1.0; + j -= half; + j *= half / (half - c); + j += half; + } else { + half = (double) num / 2.0; + j -= half; + j *= (half + c) / half; + j += half; + } + + if (j < 0.0) j = 0.0; + + /* gamma */ + + g = 1.0 / (double) g; + + if (g == 1.0) { + val = (int) j; + } else { + val = (int) (pow (j / (double)num, g) * (double)num + 0.5); + } + + /* brightness */ + + b *= scale; + + val += (int)b; + if (val > num) val = num; + if (val < 0) val = 0; + + val <<= shift; + return (unsigned short) val; + +} /* computeVal() */ |