/*++ Copyright (c) 1996-1997 Cirrus Logic, Inc. Copyright (c) 1996-1997 Microsoft Corporation. Module Name: G A M M A . C Abstract: While the DAC may generate a linear relationship between the value of a color and the visual appearence of that color, the human eyes do not work in the same manner. The process done by this module manipulates the meaning of colors to get the visual linearity effect. We cannot use float or double data type in the display driver; therefore, we need implement our MATH functions. Also, the driver binary size will increase around 30KB if we use the math functions. Registry subdirectory : System\CurrentControlSet\Services\cirrus\Device0 Keys : "G Gamma", and "G Contrast" Environment: Kernel mode only Notes: * * * chu01 12-16-96 Enable color correction, Start coding * myf29 02-12-97 Support Gamma correction for 755x * * --*/ //--------------------------------------------------------------------------- // HEADER FILES //--------------------------------------------------------------------------- #include "precomp.h" #ifdef GAMMACORRECT BOOL bEnableGammaCorrect(PPDEV ppdev); //--------------------------------------------------------------------------- // MACRO DEFINITION //--------------------------------------------------------------------------- #define FIXEDPREC 10 #define FIXEDFUDGE (0x01L << FIXEDPREC) #define FIXEDIMASK (0xFFFFFFFFL << FIXEDPREC) #define FIXEDFMASK (~FIXEDIMASK) #define FixedSign(x) (((x) < 0x00000000) ? -1L : 1L) #define FixedAbs(x) (((x) < 0x00000000) ? -(x) : (x)) #define FixedMakeInt(x) (((long) x)*FIXEDFUDGE) #define FixedTrunc(x) ((long) ((x) & FIXEDIMASK)) #define FixedRound(x) (FixedTrunc((x) + (FIXEDFUDGE >> 1))) #define FixedInt(x) ((x) /FIXEDFUDGE) #define FixedFract(x) ((((FixedAbs(x)) - FixedTrunc(FixedAbs(x)))*1000)/FIXEDFUDGE) #define FixedAdd(x,y) ((x) + (y)) #define FixedSub(x,y) ((x) - (y)) #define FixedMul(x,y) ((((x) * (y))+(FIXEDFUDGE >> 1))/FIXEDFUDGE) #define FixedDiv(x,y) (long) ((y==0) ? 0x7FFFFFFFL : ((x)*FIXEDFUDGE) / (y)) //--------------------------------------------------------------------------- // VARABLES //--------------------------------------------------------------------------- PGAMMA_VALUE GammaFactor ; // gamma facter for All, Blue, Green, Red PCONTRAST_VALUE ContrastFactor ; // contrast facter for All, Blue, Green, Red //------------------------------------------------------------------------------ // // Function: UCHAR GammaCorrect(UCHAR gamma, UCHAR v) // { // UCHAR dv; // dv = (UCHAR)(256 * pow(v/256.0, pow(10, (gamma - 128)/128.0))); // return dv; // } // // Input: // gamma: new gamma factor from 0 to 255 // color: color value for Red, Green, or Blue // // Output: // dv: new color value after gamma correction // //------------------------------------------------------------------------------ UCHAR GammaCorrect(UCHAR gamma, UCHAR v) { UCHAR dv ; long Color, GammaF, Result ; DISPDBG((4, "GammaCorrect")) ; if ((gamma == 128) || (gamma == 127) || (gamma == 126)) return v ; Color = FixedDiv(v, 256) ; // old color value if (Color == 0L) // in case then we don't need go though calculation return 0 ; GammaF = FixedDiv(gamma-128, 128) ; // new gamma factor Result = Power(Color, Power(FixedMake(10, 0, 1000), GammaF)) ; Result = (long)FixedInt(FixedMul(FixedMake(256, 0, 1000), Result)) ; dv = (UCHAR)Result ; return dv ; } // GammaCorrect //------------------------------------------------------------------------------ // Function:long Power(long Base, long Exp) // // Input: // Base: base number of power function // Exp: exponential number // // Output: // 20 bits format of integer and fraction number // 0 = not use(or sign), // i = integer portion, // f = fraction portion // 0 + i + f = 32 bits // format = 000000000000iiiiiiiiiiiiiiiiiiiffffffffffffffffffff // //------------------------------------------------------------------------------ long Power(long Base, long Exp) { int i, iSignExp; long lResult, lResultFract, lRoot; iSignExp = FixedSign(Exp); // get sing bit Exp = FixedAbs(Exp); // convert to positive // calculate integer expression lResult = FixedMakeInt(1); for(i = 0; i < FixedInt(Exp); i++) lResult = FixedMul(lResult,Base); // calculate fraction expression and add to integer result if(FixedFract(Exp) != 0) { lResultFract = FixedMakeInt(1); lRoot = FixedAbs(Base); for(i = 0x0; i < FIXEDPREC; i++) { lRoot = FixedSqrt(lRoot); if(((0x01L << (FIXEDPREC - 1 - i)) & Exp) != 0) { lResultFract = FixedMul(lResultFract, lRoot); } } lResult = FixedMul(lResult, lResultFract); } if(iSignExp == -1) lResult = FixedDiv(FixedMakeInt(1), lResult); return(lResult); } // Power //------------------------------------------------------------------------------ // // Function:long FixedMake(long x, long y, long z) // // Input: // x: integer portion of the number // y: fraction portion of the number // z: precison after decimal // // Output: // 20 bits format of integer and fraction number // 0 = not use(or sign), // i = integer portion, // f = fraction portion // 0 + i + f = 32 bits // format = 000000000000iiiiiiiiiiiiiiiiiiiffffffffffffffffffff // //------------------------------------------------------------------------------ long FixedMake(long x, long y, long z) { DISPDBG((4, "FixedMake")) ; if (x == 0) return((y * FIXEDFUDGE) / z); else return(FixedSign(x) * ((FixedAbs(x)*FIXEDFUDGE) | (((y * FIXEDFUDGE)/ z) & FIXEDFMASK))); } // FixedMake //------------------------------------------------------------------------------ // // Function:long FixedSqrt(long Root) // // Input: // Root: number to square // // Output: // 20 bits format of integer and fraction number // 0 = not use(or sign), // i = integer portion, // f = fraction portion // 0 + i + f = 32 bits // format = 000000000000iiiiiiiiiiiiiiiiiiiffffffffffffffffffff // //------------------------------------------------------------------------------ long FixedSqrt(long Root) { long lApprox; long lStart; long lEnd; if(FixedSign(Root) != 1) return(0); lStart = (long) FixedMakeInt(1); lEnd = Root; if(Root < lStart) { lEnd = lStart; lStart = Root; } lApprox = (lStart + lEnd) / 2; while(lStart != lEnd) { lApprox = (lStart + lEnd) / 2; if ((lApprox == lStart) || (lApprox == lEnd)) { lStart = lEnd = lApprox; } else { if(FixedMul(lApprox, lApprox) < Root) { lStart = lApprox; } else { lEnd = lApprox; } } } // end of while return(lApprox); } // // C O N T R A S T F A C T O R // //------------------------------------------------------------------------------ // // Function:long CalcContrast(UCHAR contrast, UCHAR v) // // Input: // // Output: // //------------------------------------------------------------------------------ UCHAR CalcContrast(UCHAR contrast, UCHAR v) { int dv; dv = ((((int)v - 128) * (int)contrast) / 128) + 128 ; if(dv < 0) dv = 0; if(dv > 255) dv = 255; return (unsigned char)dv; } // CalcContrast // // G A M M A F A C T O R // //--------------------------------------------------------------------------- // // Routine Description: // // Arguments: // // Palette: Pointer to palette array // NumberOfEntryes: Number of palette entries need modified // // Return Value: // // None // //--------------------------------------------------------------------------- VOID CalculateGamma( PDEV* ppdev, PVIDEO_CLUT pScreenClut, long NumberOfEntries ) { UCHAR GammaRed, GammaGreen, GammaBlue, Red, Green, Blue ; UCHAR Contrast, ContrastRed, ContrastGreen, ContrastBlue ; UCHAR Brightness ; int PalSegment, PalOffset, i ; int iGamma ; PALETTEENTRY* ppalSrc ; PALETTEENTRY* ppalDest ; PALETTEENTRY* ppalEnd ; DISPDBG((2, "CalculateGamma")) ; Brightness = (LONG) GammaFactor >> 24 ; GammaBlue = (LONG) GammaFactor >> 16 ; GammaGreen = (LONG) GammaFactor >> 8 ; GammaRed = (LONG) GammaFactor >> 0 ; iGamma = (int)(Brightness - 128) + (int)GammaRed ; GammaRed = (UCHAR)iGamma ; if (iGamma < 0) GammaRed = 0 ; if (iGamma > 255) GammaRed = 255 ; iGamma = (int)(Brightness - 128) + (int)GammaGreen ; GammaGreen = (UCHAR)iGamma ; if (iGamma < 0) GammaGreen = 0 ; if (iGamma > 255) GammaGreen = 255 ; iGamma = (int)(Brightness - 128) + (int)GammaBlue ; GammaBlue = (UCHAR)iGamma ; if (iGamma < 0) GammaBlue = 0 ; if (iGamma > 255) GammaBlue = 255 ; Contrast = (LONG) ContrastFactor >> 0 ; ppalDest = (PALETTEENTRY*) pScreenClut->LookupTable; ppalEnd = &ppalDest[NumberOfEntries]; i = 0 ; for (; ppalDest < ppalEnd; ppalDest++, i++) { Red = ppalDest->peRed ; Green = ppalDest->peGreen ; Blue = ppalDest->peBlue ; Red = GammaCorrect(GammaRed, Red) ; Green = GammaCorrect(GammaGreen, Green) ; Blue = GammaCorrect(GammaBlue, Blue) ; Red = CalcContrast(Contrast, Red) ; Green = CalcContrast(Contrast, Green) ; Blue = CalcContrast(Contrast, Blue) ; if (ppdev->iBitmapFormat == BMF_8BPP) { ppalDest->peRed = Red >> 2 ; ppalDest->peGreen = Green >> 2 ; ppalDest->peBlue = Blue >> 2 ; } else if ((ppdev->iBitmapFormat == BMF_16BPP) || (ppdev->iBitmapFormat == BMF_24BPP)) { ppalDest->peRed = Red ; ppalDest->peGreen = Green ; ppalDest->peBlue = Blue ; } } return ; } // CalulateGamma /******************************************************************************\ * * Function: bEnableGammaCorrect * * Enable GammaTable. Called from DrvEnableSurface. * * Parameters: ppdev Pointer to phsyical device. * * Returns: TRUE : successful; FALSE: fail * \******************************************************************************/ BOOL bEnableGammaCorrect(PDEV* ppdev) { BYTE srIndex, srData ; BYTE* pjPorts = ppdev->pjPorts ; int i ; DISPDBG((4, "bEnableGammaCorrect")) ; // // Enable Gamma correction. If needed; Otherwise, turn it off. // srIndex = CP_IN_BYTE(pjPorts, SR_INDEX) ; // i 3c4 srIndex CP_OUT_BYTE(pjPorts, SR_INDEX, 0x12) ; // o 3c4 12 srData = CP_IN_BYTE(pjPorts, SR_DATA) ; // i 3c5 srData if (ppdev->flCaps & CAPS_GAMMA_CORRECT) { if ((ppdev->iBitmapFormat == BMF_16BPP) || (ppdev->iBitmapFormat == BMF_24BPP)) srData |= 0x40 ; // 3c5.12.D6 = 1 else srData &= 0xBF ; // 3c5.12.D6 = 0 } else srData &= 0xBF ; // 3c5.12.D6 = 0 CP_OUT_BYTE(pjPorts, SR_DATA, srData) ; // o 3c5 srData CP_OUT_BYTE(pjPorts, SR_INDEX, srIndex) ; // o 3c4 srIndex if ( srData & 0x40 ) { return TRUE ; } else { return FALSE ; } } // bEnableGammaCorrect //myf29 : for 755x Gamma Correct support begin /******************************************************************************\ * * Function: bEnableGamma755x * * Enable Graphic GammaTable. Called from DrvAssertMode/DrvEscape * * Parameters: ppdev Pointer to phsyical device. * * Returns: TRUE : successful; FALSE: fail * \******************************************************************************/ BOOL bEnableGamma755x(PDEV* ppdev) { BYTE crIndex, crData ; BYTE* pjPorts = ppdev->pjPorts ; BOOL status; DISPDBG((4, "bEnableGamma755x")) ; // // Enable Gamma correction. If needed; Otherwise, turn it off. // crIndex = CP_IN_BYTE(pjPorts, CRTC_INDEX) ; // i 3d4 crIndex status = FALSE; if (ppdev->flCaps & CAPS_GAMMA_CORRECT) { CP_OUT_BYTE(pjPorts, CRTC_INDEX, 0x8E); // CR8E[2]=0 crData = CP_IN_BYTE(pjPorts, CRTC_DATA); if ((ppdev->iBitmapFormat == BMF_16BPP) || (ppdev->iBitmapFormat == BMF_24BPP)) { crData &= 0xFB ; // CR8E[2] = 0 status = TRUE; } else crData |= 0x04 ; // CR8E[2] = 1 CP_OUT_BYTE(pjPorts, CRTC_DATA, crData) ; // o 3d5 crData } CP_OUT_BYTE(pjPorts, CRTC_INDEX, crIndex) ; // o 3d4 crIndex return(status); } // bEnableGamma755x /******************************************************************************\ * * Function: bEnableGammaVideo755x * * Enable Video GammaTable. Called from DrvAssertMode/DrvEscape * * Parameters: ppdev Pointer to phsyical device. * * Returns: TRUE : successful; FALSE: fail * \******************************************************************************/ BOOL bEnableGammaVideo755x(PDEV* ppdev) { BYTE crIndex, crData ; BYTE* pjPorts = ppdev->pjPorts ; BOOL status; DISPDBG((4, "bEnableGammaVideo755x")) ; // // Enable Gamma correction. If needed; Otherwise, turn it off. // crIndex = CP_IN_BYTE(pjPorts, CRTC_INDEX) ; // i 3d4 crIndex status = FALSE; if (ppdev->flCaps & CAPS_GAMMA_CORRECT) { CP_OUT_BYTE(pjPorts, CRTC_INDEX, 0x36); // CR36[6]=1:enable VW LUT crData = CP_IN_BYTE(pjPorts, CRTC_DATA); // if ((ppdev->iBitmapFormat == BMF_16BPP) || // (ppdev->iBitmapFormat == BMF_24BPP)) { crData |= 0x40 ; // CR36[6] = 1 CP_OUT_BYTE(pjPorts, CRTC_DATA, crData); CP_OUT_BYTE(pjPorts, CRTC_INDEX, 0x3F) ; // CR3F[4]=1:select VW crData = CP_IN_BYTE(pjPorts, CRTC_DATA); crData |= 0x10 ; // CR3F[4] = 1 CP_OUT_BYTE(pjPorts, CRTC_DATA, crData); status = TRUE; } } CP_OUT_BYTE(pjPorts, CRTC_INDEX, crIndex) ; // o 3d4 crIndex return(status); } // bEnableGammaVideo755x //myf29 end #endif // GAMMACORRECT