diff --git a/AdobeGammaTest.icm b/AdobeGammaTest.icm new file mode 100644 index 0000000..e5f1246 Binary files /dev/null and b/AdobeGammaTest.icm differ diff --git a/Makefile b/Makefile index 4d063e6..dacc95b 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ # Makefile for xcalib # -# (c) 2004 Stefan Doehla +# (c) 2004-2005 Stefan Doehla # # This program is GPL-ed postcardware! please see README # @@ -20,12 +20,36 @@ # MA 02111-1307 USA. # -XCALIB_VERSION = 0.5 +# +# the following targets are defined: +# - lo_xcalib +# xcalib in its standard version (internal parser) +# - icclib_xcalib +# xcalib using Graeme Gill's icclib +# - lcms_xcalib +# xcalib using a patched version of Marti Maria's LCMS +# - win_xcalib +# version for MS-Windows systems with MinGW (internal parser) +# - fglrx_xcalib +# version for ATI's proprietary fglrx driver (internal parser) +# +# - clean +# delete all objects and binaries +# - dist +# create .tar.gz archive +# +# if it doesn't compile right-out-of-the-box, it may be sufficient +# to change the following variables + +XCALIB_VERSION = 0.6 CFLAGS = -Os XINCLUDEDIR = /usr/X11R6/include XLIBDIR = /usr/X11R6/lib LCMSINCLUDEDIR = /usr/local/include LCMSLIBDIR = /usr/local/lib +# for ATI's proprietary driver (must contain the header file fglrx_gamma.h) +FGLRXINCLUDEDIR = ./fglrx +FGLRXLIBDIR = ./fglrx # default make target all: lo_xcalib @@ -36,6 +60,10 @@ lo_xcalib: xcalib.c $(CC) $(CFLAGS) -c xcalib.c -I$(XINCLUDEDIR) -DXCALIB_VERSION=\"$(XCALIB_VERSION)\" $(CC) $(CFLAGS) -L$(XLIBDIR) -lm -o xcalib xcalib.o -lX11 -lXxf86vm -lXext +fglrx_xcalib: xcalib.c + $(CC) $(CFLAGS) -c xcalib.c -I$(XINCLUDEDIR) -DXCALIB_VERSION=\"$(XCALIB_VERSION)\" -I$(FGLRXINCLUDEDIR) -DFGLRX + $(CC) $(CFLAGS) -L$(XLIBDIR) -L$(FGLRXLIBDIR) -lm -o xcalib xcalib.o -lX11 -lXxf86vm -lXext -lfglrx_gamma + win_xcalib: xcalib.c $(CC) $(CFLAGS) -c xcalib.c -DXCALIB_VERSION=\"$(XCALIB_VERSION)\" -DWIN32GDI windres.exe resource.rc resource.o @@ -68,6 +96,6 @@ clean: dist: cd .. - tar czf xcalib-source-$(XCALIB_VERSION).tar.gz xcalib-$(XCALIB_VERSION) + tar czf xcalib-source-$(XCALIB_VERSION).tar.gz xcalib-$(XCALIB_VERSION)/ cd xcalib-$(XCALIB_VERSION)/ diff --git a/README b/README index 3f7de9f..b661fc0 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -xcalib 0.5 +Xcalib 0.6 ==================================================== (c) 2004-2005 Stefan Döhla This program is GPL-licensed postcardware! More infos at end of README. @@ -23,13 +23,14 @@ usage: -noaction or -n -verbose or -v -printramps or -p + -loss or -l -help or -h -version - last parameter MUST be an ICC profile containing vcgt-tag + last parameter MUST be an ICC profile containing a vcgt or mLUT tag. use profiles gamma_1_0.icc and gamma_2_2.icc for testing. Profiles - with vcg-tables can be created with some profile creation suites. + with vcg-tables can be created with most profile creation suites. An example profile with a vcg-table is inclued, named bluish.icc, which simulates a very high whitepoint (without further intentions). @@ -40,6 +41,12 @@ requirements: is available. Other X-servers like OpenWin do not contain XVidMode stuff - so please don't ask me for support if XVidMode isn't supported. + + Since version 0.5, Win32-support was added. The program will work + with most video cards, that have correctly implemented drivers. + + As of version 0.6, a special treatment for the close-source ATI FGLRX + X11 driver was added. XVidMode is still required. You need a profile which contains the 'vcgt' tag to achieve monitor calibration. You can create it with some commercial @@ -57,6 +64,9 @@ install: $ make lcms_xcalib $ make lo_xcalib + $ make win_xcalib + $ make fglrx_xcalib + The make targets correspond to the possible ICC reader implementations: - Graeme Gill's "icclib" @@ -83,13 +93,21 @@ install: The Win32 version was made with and tested for MinGW. Since most users do not have a running MinGW environment, a binary executable is - provided. To compile it on yout own, the following command creates a + provided. To compile it on your own, the following command creates a working Win32-build (tested with MSys): $ make win_xcalib Win32 was only tested with the internal parser - lcms and icclib support are not planned. + + For ATI's proprietary FGLRX driver for X11, a special version can be + built. Issue the command + + $ make fglrx_xcalib + + on the commandline. For now, only the internal parser can be used + in combination with this server backend. motivation: ----------- @@ -124,6 +142,7 @@ motivation: live with it since it's common. They use a tag called Video Card Gamma Tag (or vcgt) in ICC-profiles that contains calibration values. The calibration is applied before profile creation, where the vcgt + will be saved in your profile for convenience reasons: All color settings for the display device are stored in a common file. @@ -160,6 +179,7 @@ limitations: Known not-working drivers: - vesa (generic driver without any calibration knobs) + - fglrx (but you can build fglrx_xcalib) If you see both/only one/no display changing it's behaviour, test if it's a bug of xcalib by cross-checking with the 'xgamma' tool that @@ -169,10 +189,36 @@ limitations: vcgt. The vcgt contains 2.2 in all cases, whereas the real LUT-values that are downloaded to the X-server are located somewhere else in the system - but nobody know's where. Please tell me where they are - if - you find them. + you find them. A newer version of AdobeGamma (from 2003) writes a + vcgt tag with useful data. Nevertheless, the size field is wrong. As + of version 0.6, basic concealment for wrong AdobeGamma profiles + (created with the 2003 version) was added to the internal parser. + + On Win32-systems, some drivers are not correctly implemented. E.g. + the NVidia Riva driver for Windows2000 and WindowsXP wrote nonsense + values to the video cards RAMDAC (resulting in a gray display). I + used for these cards an old NT-driver from a video card vendor. + + The source code became messy in the last time because of numerous + workarounds and a bad mixture of Win32, X11, ATI code and code for + the different parsers used to get the gamma ramps from the profile. + This makes it hard to find the important code sections for others + than me and might have lead to bugs or leaks. A following version + will most likely be ported to C++ to ease modularisation of the code + and allow utilization by other software. history: -------- + 0.6: + - added 0-interpolated upscaling if LUT>vcgt + - added reading of mLUT instead of vcgt (not memory-safe for now) + this is used for profiles, created by ProfileMechanic Monitor + - added concealment for obviously wrong profiles made by AdobeGamma + - added fglrx version for ATI's proprietary driver + - added loss calculation (option "-loss" or "-l") which shows how + many steps are lost by calibrating the device + - added limits of VideoCardGammaFormula to internal parser + 0.5: 2005-03-03 - Win32 version added (compilable with MinGW) + support for command line options as usual @@ -218,11 +264,15 @@ history: todo: ----- - [ ] gamma limits of vcgt-spec need to be implemented + [ ] integrate the _ICC_PROFILE atom + [ ] interpolated upscaling + [X] use ATI's API when using the closed-source X11 ATI driver + [ ] gamma limits of vcgt-spec for icclib and LCMS version [ ] further code review for memory leaks [x] use platform independent types for better portability [X] use lcms instead of icclib: worse vcgt-parsing but functions for gamma ramp building and smoothing + [ ] add multi-monitor support to Win32 version bugs: ----- @@ -260,6 +310,7 @@ links: http://www.littlecms.com http://www.argyllcms.com http://www.coloraid.de + http://www.behrmann.name license: -------- @@ -273,6 +324,6 @@ license: GERMANY Please write on it your name and email-address and that you use - xcalib-0.5 . + xcalib-0.6 . EOF diff --git a/README.profilers b/README.profilers index 3665508..b0c14de 100644 --- a/README.profilers +++ b/README.profilers @@ -9,7 +9,7 @@ BasiCColor display: ------------------- vcgt, table with 256 * 16bit entries -Gretag ProfileMaker 4.1: +Gretag/Logo ProfileMaker 4.1: ------------------------ vcgt, table with 256 * 16bit entries @@ -17,5 +17,14 @@ lprof, Marti's little profiler (unmaintained): ---------------------------------------------- no calibration +Profile Mechanic Monitor (by Jonathan Sachs) +-------------------------------------------- +mLUT, table with 256 * 16bit entries + +AdobeGamma (came with Photoshop CS) +----------------------------------- +vcgt, table with 256 * 16bit entries, signalled as 8bit entries! + + (c) 2005 - Stefan Doehla EOF diff --git a/fglrx/fglrx_gamma.h b/fglrx/fglrx_gamma.h new file mode 100644 index 0000000..c139d5b --- /dev/null +++ b/fglrx/fglrx_gamma.h @@ -0,0 +1,83 @@ +/*****************************************************************************/ +/* */ +/* NAME: fglrx_gamma.h */ +/* */ +/* FGLRXGAMMA extension interface library */ +/* */ +/* Copyright (c) 2002,2003 ATI Research, Starnberg, Germany */ +/* */ +/*****************************************************************************/ + +#ifndef __FGLRX_GAMMA_H__ +#define __FGLRX_GAMMA_H__ + +////////////////////////////////////////////////////////////////////////////// +// includes + +#include + + +////////////////////////////////////////////////////////////////////////////// +// macro defines + +// boolean constants +#define FALSE (1==0) +#define TRUE (1==1) + +// ordinal constants +#define FGLRX_GAMMA_RAMP_SIZE 256 + + +////////////////////////////////////////////////////////////////////////////// +// type defines + +// basic types +typedef unsigned long DWORD; +typedef unsigned long ULONG; +typedef unsigned int UINT; +typedef unsigned int HANDLE; +#ifndef ULONG_PTR +typedef ULONG ULONG_PTR; +#endif // ULONG_PTR + +// structured types +typedef XF86VidModeGamma FGLRX_X11Gamma_float; + +typedef struct { + UINT red; /* red color value for gamma correction table */ + UINT green; /* green color value for gamma correction table */ + UINT blue; /* blue color value for gamma correction table */ +} FGLRX_X11Gamma_UINT, FGLRX_X11Gamma_uint_1024; + +typedef struct { + CARD16 red; /* red color value for gamma correction table */ + CARD16 green; /* green color value for gamma correction table */ + CARD16 blue; /* blue color value for gamma correction table */ +} FGLRX_X11Gamma_C16, FGLRX_X11Gamma_C16_1024; + +typedef struct { + CARD16 RGamma[FGLRX_GAMMA_RAMP_SIZE]; /* red color value for gamma correction table */ + CARD16 GGamma[FGLRX_GAMMA_RAMP_SIZE]; /* green color value for gamma correction table */ + CARD16 BGamma[FGLRX_GAMMA_RAMP_SIZE]; /* blue color value for gamma correction table */ +} FGLRX_X11Gamma_C16native, FGLRX_X11Gamma_C16native_1024; + + +////////////////////////////////////////////////////////////////////////////// +// exported functions from libfglrx_gamma.h + +extern Bool FGLRX_X11SetGammaRamp_float + (Display *dpy, int screen, int controller, int size, FGLRX_X11Gamma_float *Gamma); +extern Bool FGLRX_X11SetGammaRamp_uint_1024 + (Display *dpy, int screen, int controller, int size, FGLRX_X11Gamma_uint_1024 *Gamma); +extern Bool FGLRX_X11SetGammaRamp_C16_1024 + (Display *dpy, int screen, int controller, int size, FGLRX_X11Gamma_C16_1024 *Gamma); +extern Bool FGLRX_X11SetGammaRamp_C16native_1024 + (Display *dpy, int screen, int controller, int size, FGLRX_X11Gamma_C16native_1024 *Gamma); + +extern Bool FGLRX_X11GetGammaRampSize + (Display *dpy, int screen, int *size); + +#endif /* __FGLRX_GAMMA_H__ */ + +////////////////////////////////////////////////////////////////////////////// +// EOF diff --git a/fglrx/libfglrx_gamma.a b/fglrx/libfglrx_gamma.a new file mode 100644 index 0000000..0f1258e Binary files /dev/null and b/fglrx/libfglrx_gamma.a differ diff --git a/fglrx/libfglrx_gamma.so.1.0 b/fglrx/libfglrx_gamma.so.1.0 new file mode 100644 index 0000000..ddab387 Binary files /dev/null and b/fglrx/libfglrx_gamma.so.1.0 differ diff --git a/gamma_2_2_bright.icc b/gamma_2_2_bright.icc new file mode 100644 index 0000000..4d46b98 Binary files /dev/null and b/gamma_2_2_bright.icc differ diff --git a/gamma_2_2_lowContrast.icc b/gamma_2_2_lowContrast.icc new file mode 100644 index 0000000..cf3e9b8 Binary files /dev/null and b/gamma_2_2_lowContrast.icc differ diff --git a/xcalib.c b/xcalib.c index e5809d9..12dd9c9 100644 --- a/xcalib.c +++ b/xcalib.c @@ -53,6 +53,9 @@ #include #include #include +#ifdef FGLRX +# include +#endif #else #include #include @@ -78,6 +81,7 @@ /* the 4-byte marker for the vcgt-Tag */ #define VCGT_TAG 0x76636774L +#define MLUT_TAG 0x6d4c5554L #ifndef XCALIB_VERSION # define XCALIB_VERSION "version unknown (>0.5)" @@ -117,10 +121,11 @@ struct xcalib_state_t { void usage (void) { - fprintf (stdout, "usage: xcalib [-options] ICCPROFILE\n"); fprintf (stdout, "Copyright (C) 2004-2005 Stefan Doehla \n"); fprintf (stdout, "THIS PROGRAM COMES WITH ABSOLUTELY NO WARRANTY!\n"); fprintf (stdout, "\n"); + fprintf (stdout, "usage: xcalib [-options] ICCPROFILE\n"); + fprintf (stdout, "\n"); fprintf (stdout, "where the available options are:\n"); #ifndef WIN32GDI fprintf (stdout, " -display or -d\n"); @@ -130,6 +135,7 @@ usage (void) fprintf (stdout, " -noaction or -n\n"); fprintf (stdout, " -verbose or -v\n"); fprintf (stdout, " -printramps or -p\n"); + fprintf (stdout, " -loss or -l\n"); fprintf (stdout, " -help or -h\n"); fprintf (stdout, " -version\n"); fprintf (stdout, "\n"); @@ -202,6 +208,58 @@ read_vcgt_from_profile(const char * filename, u_int16_t ** rRamp, u_int16_t ** g tagSize = BE_INT(cTmp); if(!bytesRead) goto cleanup_fileparser; + if(tagName == MLUT_TAG) + { + fseek(fp, 0+tagOffset, SEEK_SET); + message("mLUT found (Profile Mechanic)\n"); + redRamp = (unsigned short *) malloc ((256) * sizeof (unsigned short)); + greenRamp = (unsigned short *) malloc ((256) * sizeof (unsigned short)); + blueRamp = (unsigned short *) malloc ((256) * sizeof (unsigned short)); + { + for(j=0; j<256; j++) { + bytesRead = fread(cTmp, 1, 2, fp); + redRamp[j]= BE_SHORT(cTmp); + } + for(j=0; j<256; j++) { + bytesRead = fread(cTmp, 1, 2, fp); + greenRamp[j]= BE_SHORT(cTmp); + } + for(j=0; j<256; j++) { + bytesRead = fread(cTmp, 1, 2, fp); + blueRamp[j]= BE_SHORT(cTmp); + } + } + /* interpolate if vcgt size doesn't match video card's gamma table */ + if(*nEntries == 256) { + *rRamp = redRamp; + *gRamp = greenRamp; + *bRamp = blueRamp; + } + else if(*nEntries < 256) { + ratio = (unsigned int)(256 / (*nEntries)); + *rRamp = (unsigned short *) malloc ((*nEntries) * sizeof (unsigned short)); + *gRamp = (unsigned short *) malloc ((*nEntries) * sizeof (unsigned short)); + *bRamp = (unsigned short *) malloc ((*nEntries) * sizeof (unsigned short)); + for(j=0; j<*nEntries; j++) { + rRamp[0][j] = redRamp[ratio*j]; + gRamp[0][j] = greenRamp[ratio*j]; + bRamp[0][j] = blueRamp[ratio*j]; + } + } + /* interpolation of zero order - TODO: at least bilinear */ + else if(*nEntries > 256) { + ratio = (unsigned int)((*nEntries) / 256); + *rRamp = (unsigned short *) malloc ((*nEntries) * sizeof (unsigned short)); + *gRamp = (unsigned short *) malloc ((*nEntries) * sizeof (unsigned short)); + *bRamp = (unsigned short *) malloc ((*nEntries) * sizeof (unsigned short)); + for(j=0; j<*nEntries; j++) { + rRamp[0][j] = redRamp[j/ratio]; + gRamp[0][j] = greenRamp[j/ratio]; + bRamp[0][j] = blueRamp[j/ratio]; + } + } + goto cleanup_fileparser; + } if(tagName == VCGT_TAG) { fseek(fp, 0+tagOffset, SEEK_SET); @@ -245,6 +303,16 @@ read_vcgt_from_profile(const char * filename, u_int16_t ** rRamp, u_int16_t ** g uTmp = BE_INT(cTmp); bMax = (float)uTmp/65536.0; + if(rGamma > 5.0 || gGamma > 5.0 || bGamma > 5.0) + error("Gamma values out of range (> 5.0): \nR: %f \tG: %f \t B: %f", + rGamma, gGamma, bGamma); + if(rMin >= 1.0 || gMin >= 1.0 || bMin >= 1.0) + error("Gamma lower limit out of range (>= 1.0): \nRMin: %f \tGMin: %f \t BMin: %f", + rMin, gMin, bMin); + if(rMax > 1.0 || gMax > 1.0 || bMax > 1.0) + error("Gamma upper limit out of range (> 1.0): \nRMax: %f \tGMax: %f \t BMax: %f", + rMax, gMax, bMax); + message("Red: Gamma %f \tMin %f \tMax %f\n", rGamma, rMin, rMax); message("Green: Gamma %f \tMin %f \tMax %f\n", gGamma, gMin, gMax); message("Blue: Gamma %f \tMin %f \tMax %f\n", bGamma, bMin, bMax); @@ -253,21 +321,18 @@ read_vcgt_from_profile(const char * filename, u_int16_t ** rRamp, u_int16_t ** g *gRamp = (unsigned short *) malloc ((*nEntries) * sizeof (unsigned short)); *bRamp = (unsigned short *) malloc ((*nEntries) * sizeof (unsigned short)); for(j=0; j<*nEntries; j++) { - rRamp[0][j] = 65563 * - (double) pow ((double) j / - (double) (*nEntries), - rGamma * - (double) SYSTEM_GAMMA); - gRamp[0][j] = 65563 * - (double) pow ((double) j / - (double) (*nEntries), - gGamma * - (double) SYSTEM_GAMMA); - bRamp[0][j] = 65563 * - (double) pow ((double) j / - (double) (*nEntries), - bGamma * - (double) SYSTEM_GAMMA); + rRamp[0][j] = 65536 * + ((double) pow ((double) j * (rMax - rMin) / (double) (*nEntries), + rGamma * (double) SYSTEM_GAMMA + ) + rMin); + gRamp[0][j] = 65536 * + ((double) pow ((double) j * (gMax - gMin) / (double) (*nEntries), + gGamma * (double) SYSTEM_GAMMA + ) + gMin); + bRamp[0][j] = 65536 * + ((double) pow ((double) j * (bMax - bMin) / (double) (*nEntries), + bGamma * (double) SYSTEM_GAMMA + ) + bMin); } } /* VideoCardGammaTable */ @@ -279,9 +344,17 @@ read_vcgt_from_profile(const char * filename, u_int16_t ** rRamp, u_int16_t ** g bytesRead = fread(cTmp, 1, 2, fp); entrySize = BE_SHORT(cTmp); + /* conecealment for AdobeGamma-Profiles */ + if(tagSize == 1584) { + entrySize = 2; + numEntries = 256; + numChannels = 3; + } + message ("channels: \t%d\n", numChannels); message ("entry size: \t%dbits\n",entrySize * 8); message ("entries/channel: \t%d\n", numEntries); + message ("tag size: \t%d\n", tagSize); if(numChannels!=3) /* assume we have always RGB */ goto cleanup_fileparser; @@ -327,17 +400,12 @@ read_vcgt_from_profile(const char * filename, u_int16_t ** rRamp, u_int16_t ** g } } } + *rRamp = (unsigned short *) malloc ((*nEntries) * sizeof (unsigned short)); + *gRamp = (unsigned short *) malloc ((*nEntries) * sizeof (unsigned short)); + *bRamp = (unsigned short *) malloc ((*nEntries) * sizeof (unsigned short)); /* interpolate if vcgt size doesn't match video card's gamma table */ - if(*nEntries == numEntries) { - *rRamp = redRamp; - *gRamp = greenRamp; - *bRamp = blueRamp; - } - else if(*nEntries < numEntries) { + if(*nEntries <= numEntries) { ratio = (unsigned int)(numEntries / (*nEntries)); - *rRamp = (unsigned short *) malloc ((*nEntries) * sizeof (unsigned short)); - *gRamp = (unsigned short *) malloc ((*nEntries) * sizeof (unsigned short)); - *bRamp = (unsigned short *) malloc ((*nEntries) * sizeof (unsigned short)); for(j=0; j<*nEntries; j++) { rRamp[0][j] = redRamp[ratio*j]; gRamp[0][j] = greenRamp[ratio*j]; @@ -347,15 +415,15 @@ read_vcgt_from_profile(const char * filename, u_int16_t ** rRamp, u_int16_t ** g /* interpolation of zero order - TODO: at least bilinear */ else if(*nEntries > numEntries) { ratio = (unsigned int)((*nEntries) / numEntries); - *rRamp = (unsigned short *) malloc ((*nEntries) * sizeof (unsigned short)); - *gRamp = (unsigned short *) malloc ((*nEntries) * sizeof (unsigned short)); - *bRamp = (unsigned short *) malloc ((*nEntries) * sizeof (unsigned short)); for(j=0; j<*nEntries; j++) { rRamp[0][j] = redRamp[j/ratio]; gRamp[0][j] = greenRamp[j/ratio]; bRamp[0][j] = blueRamp[j/ratio]; } } + free(redRamp); + free(greenRamp); + free(blueRamp); } goto cleanup_fileparser; } @@ -398,11 +466,14 @@ main (int argc, char *argv[]) #endif struct xcalib_state_t * x = NULL; int rv = 0; - u_int16_t *r_ramp, *g_ramp, *b_ramp; + u_int16_t *r_ramp = NULL, *g_ramp = NULL, *b_ramp = NULL; int i; int clear = 0; int donothing = 0; int printramps = 0; + int calcloss = 0; + u_int16_t tmpRampVal = 0; + unsigned int r_res, g_res, b_res; unsigned int ramp_size = 256; unsigned int ramp_scaling; @@ -413,6 +484,9 @@ main (int argc, char *argv[]) Display *dpy = NULL; int screen = -1; char *displayname = NULL; +#ifdef FGLRX + FGLRX_X11Gamma_C16native fglrx_gammaramps; +#endif #else char win_default_profile[MAX_PATH+1]; DWORD win_profile_len; @@ -481,6 +555,11 @@ main (int argc, char *argv[]) printramps = 1; continue; } + /* print ramps to stdout */ + if (!strcmp (argv[i], "-l") || !strcmp (argv[i], "-loss")) { + calcloss = 1; + continue; + } /* clear gamma lut */ if (!strcmp (argv[i], "-c") || !strcmp (argv[i], "-clear")) { clear = 1; @@ -528,7 +607,10 @@ main (int argc, char *argv[]) #ifndef WIN32GDI /* X11 initializing */ if ((dpy = XOpenDisplay (displayname)) == NULL) { - error ("Can't open display %s", XDisplayName (displayname)); + if(!donothing) + error ("Can't open display %s", XDisplayName (displayname)); + else + warning("Can't open display %s", XDisplayName (displayname)); } else if (screen == -1) screen = DefaultScreen (dpy); @@ -538,7 +620,16 @@ main (int argc, char *argv[]) gamma.green = 1.0; gamma.blue = 1.0; if (clear) { +#ifndef FGLRX if (!XF86VidModeSetGamma (dpy, screen, &gamma)) { +#else + for(i = 0; i < 256; i++) { + fglrx_gammaramps.RGamma[i] = i << 2; + fglrx_gammaramps.GGamma[i] = i << 2; + fglrx_gammaramps.BGamma[i] = i << 2; + } + if (!FGLRX_X11SetGammaRamp_C16native_1024(dpy, screen, -1, 256, &fglrx_gammaramps)) { +#endif XCloseDisplay (dpy); error ("Unable to reset display gamma"); } @@ -546,9 +637,18 @@ main (int argc, char *argv[]) } /* get number of entries for gamma ramps */ +#ifndef FGLRX if (!XF86VidModeGetGammaRampSize (dpy, screen, &ramp_size)) { +#else + if (!FGLRX_X11GetGammaRampSize(dpy, screen, &ramp_size)) { +#endif XCloseDisplay (dpy); - error ("Unable to query gamma ramp size"); + if(!donothing) + error ("Unable to query gamma ramp size"); + else { + warning ("Unable to query gamma ramp size"); + ramp_size = 256; + } } #else if(!hDc) @@ -688,17 +788,17 @@ main (int argc, char *argv[]) g_ramp = (unsigned short *) malloc ((ramp_size + 1) * sizeof (unsigned short)); b_ramp = (unsigned short *) malloc ((ramp_size + 1) * sizeof (unsigned short)); - ramp_scaling = 65563 / ramp_size; + ramp_scaling = 65536 / ramp_size; /* maths for gamma calculation: use system gamma as reference */ for (i = 0; i < ramp_size; i++) { - r_ramp[i] = 65563 * (double) + r_ramp[i] = 65536 * (double) pow ((double) i / (double) ramp_size, ob->u.formula.redGamma * (double) SYSTEM_GAMMA); - g_ramp[i] = 65563 * (double) + g_ramp[i] = 65536 * (double) pow ((double) i / (double) ramp_size, ob->u.formula.greenGamma * (double) SYSTEM_GAMMA); - b_ramp[i] = 65563 * (double) + b_ramp[i] = 65536 * (double) pow ((double) i / (double) ramp_size, ob->u.formula.blueGamma * (double) SYSTEM_GAMMA); } @@ -735,7 +835,35 @@ main (int argc, char *argv[]) warning ("nonsense content in green gamma table"); if (b_ramp[i + 1] < b_ramp[i]) warning ("nonsense content in blue gamma table"); -} + } + if(calcloss) { + fprintf(stdout, "Resolution loss for %d entries:\n", ramp_size); + r_res = 0; + g_res = 0; + b_res = 0; + tmpRampVal = 0xffff; + for(i = 0; i < ramp_size; i++) { + if ((r_ramp[i] & 0xff00) != (tmpRampVal & 0xff00)) { + r_res++; + } + tmpRampVal = r_ramp[i]; + } + tmpRampVal = 0xffff; + for(i = 0; i < ramp_size; i++) { + if ((g_ramp[i] & 0xff00) != (tmpRampVal & 0xff00)) { + g_res++; + } + tmpRampVal = g_ramp[i]; + } + tmpRampVal = 0xffff; + for(i = 0; i < ramp_size; i++) { + if ((b_ramp[i] & 0xff00) != (tmpRampVal & 0xff00)) { + b_res++; + } + tmpRampVal = b_ramp[i]; + } + fprintf(stdout, "R: %d\tG: %d\t B: %d\t colors lost\n", ramp_size - r_res, ramp_size - g_res, ramp_size - b_res ); + } #ifdef WIN32GDI for (i = 0; i < ramp_size; i++) { winGammaRamp.Red[i] = r_ramp[i]; @@ -749,14 +877,24 @@ main (int argc, char *argv[]) for(i=0; i> 6; + fglrx_gammaramps.GGamma[i] = g_ramp[i] >> 6; + fglrx_gammaramps.BGamma[i] = b_ramp[i] >> 6; + } + if (!FGLRX_X11SetGammaRamp_C16native_1024(dpy, screen, -1, ramp_size, &fglrx_gammaramps)) +# else if (!XF86VidModeSetGammaRamp (dpy, screen, ramp_size, r_ramp, g_ramp, b_ramp)) +# endif #else if (!SetDeviceGammaRamp(hDc, &winGammaRamp)) #endif warning ("Unable to calibrate display"); + } #ifdef ICCLIB icco->del (icco); @@ -768,13 +906,22 @@ main (int argc, char *argv[]) cmsFreeGamma(x->gGammaTable); if(x->bGammaTable!=NULL) cmsFreeGamma(x->bGammaTable); +#else + if(r_ramp) + free(r_ramp); + if(g_ramp) + free(g_ramp); + if(b_ramp) + free(b_ramp); #endif message ("X-LUT size: \t%d\n", ramp_size); cleanupX: #ifndef WIN32GDI - XCloseDisplay (dpy); + if(dpy) + if(!donothing) + XCloseDisplay (dpy); #endif return 0;