home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection 1998 Fall: Game Toolkit / Disc.iso / SDKs / PCI Driver Development Kit / • Samples / Driver Samples / Video samples / GDX 950717 / GDX / GraphicsCoreUtils.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-20  |  17.7 KB  |  507 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        GraphicsCoreUtils.c
  3.  
  4.     Contains:    Utilities that are used by the Core and the HALs
  5.  
  6.     Written by:    Sean Williams, Kevin Williams
  7.  
  8.     Copyright:    © 1994-1995 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.          <2>     7/17/95    SW        Added GraphicsUtil GetDefaultGammaTableID()
  13.          <1>     4/15/95    SW        First Checked In
  14.  
  15. */
  16.  
  17. #include "GraphicsPriv.h"
  18. #include "GraphicsCorePriv.h"
  19. #include "GraphicsCoreUtils.h"
  20. #include "GraphicsHAL.h"
  21. #include <Types.h>
  22.  
  23.  
  24.  
  25. //=====================================================================================================
  26. //
  27. // GraphicsUtilCheckSetEntry()
  28. //    This utility routine checks to make sure that a 'VDSetEntryRecord' provided to setting/getting
  29. //    CLUT entries is valid.  The 'VDSetEntryRecord' is valid if its 'csTable' is not NULL, and that the
  30. //    range of logical addresses that it indicates should set/got is appropriate for the indicated
  31. //    absolute bit depth.
  32. //
  33. //    For this routine, the relevant fields indicated by 'VDSetEntryRecord' are:
  34. //            ->    csTable            pointer to array of 'ColorSpec'
  35. //            ->    csStart            (0 based) starting index, or -1.
  36. //                                If -1, then the 'value' field of each 'ColorSpec' entry indicates the
  37. //                                CLUT address to which the 'rgb' contents should be applied.
  38. //            ->    csCount            (0 based) number of 'ColorSpec' entries to set
  39. //
  40. //    The remaining parameters are described as follows:
  41. //
  42. //            -> bitsPerPixel        Absolute pixel depth
  43. //            <- startPosition    (0 based) The starting position in the array of ColorSpecs to set/get.
  44. //                                This is the REAL start position (Not playing any of those -1 games.)
  45. //            <- numberOfEntries    (0 based) This is the number of 'ColorSpec' entries to set/get.
  46. //            <- sequential        'true' indicates that the logical address of the entry is obtained by
  47. //                                its array index in the 'csTable'.  'false' indicates that the logical
  48. //                                address of the entry should be determined by the 'value' field of the
  49. //                                ColorSpec
  50. //=====================================================================================================
  51. GDXErr GraphicsUtilCheckSetEntry(const VDSetEntryRecord *setEntry, UInt32 bitsPerPixel,
  52.         SInt16 *startPosition, SInt16 *numberOfEntries, Boolean *sequential)
  53. {
  54.         
  55.     UInt32 maxRange;                                                // Maximum logical address
  56.     UInt32 i;                                                        // Loop control variable
  57.  
  58.     GDXErr err = kGDXErrUnknownError;                                // Assume failure
  59.         
  60.     // Make sure the ColorSpec table is valid
  61.     if (NULL == setEntry->csTable)
  62.     {
  63.         err = kGDXErrInvalidColorSpecTable;
  64.         goto ErrorExit;
  65.     }
  66.  
  67.     // Find out what flavor this is: Sequential or Indexed. Indexed is indicated by
  68.     // '-1 == setEntry->csStart'.  Additionally, if using the Indexed flavor, then the true
  69.     // 'startPosition' in the provided 'csTable' is always 0.
  70.     
  71.     if (-1 == setEntry->csStart)
  72.     {
  73.         *sequential = false;
  74.         *startPosition = 0;
  75.     }
  76.     else
  77.     {
  78.         *sequential = true;
  79.         *startPosition = setEntry->csStart;
  80.     }
  81.  
  82.     *numberOfEntries = setEntry->csCount;
  83.  
  84.     // Do range checking on the 'startPosition' and 'numberOfEntries'  The valid range depends
  85.     // on the current absolute pixel depth:
  86.     //
  87.     //        if bitsPerPixel < 16, then maxRange = (2^^bpp) - 1
  88.     //        "        "     == 16, then maxRange = 31
  89.     //        "        "     == 32, then maxRange = 255
  90.     //
  91.     // For a detailed explanation of these values, please refer elsewhere... :-)
  92.     
  93.     if (16 > bitsPerPixel)            
  94.         maxRange = (1 << bitsPerPixel) - 1;                        // 1, 2, 4, or 8 bpp
  95.     else if (16 == bitsPerPixel)
  96.         maxRange = 31;                                            // 16 bpp
  97.     else
  98.         maxRange = 255;                                            // 32 bpp
  99.         
  100.     // Do generic range checking that is not dependent on whether this is Indexed or Sequential flavor.
  101.     if ((*numberOfEntries > maxRange) || (*numberOfEntries < 0))
  102.     {
  103.         err = kGDXErrInvalidParameters;
  104.         goto ErrorExit;
  105.     }
  106.     
  107.     // Now do some flavor dependent range checking
  108.     if (*sequential)
  109.     {
  110.         // For sequential flavor, make sure that we don't go beyond 'maxRange'
  111.         if (*startPosition + *numberOfEntries > maxRange)
  112.         {
  113.                 err = kGDXErrInvalidParameters;
  114.                 goto ErrorExit;
  115.         }
  116.     }
  117.     else
  118.     {
  119.         // For indexed flavor, make sure none of the indexes exceed the maximum range
  120.         for (i = 0; i <= *numberOfEntries; i++)
  121.         {
  122.             if (setEntry->csTable[i].value > maxRange)
  123.             {
  124.                 err = kGDXErrInvalidParameters;
  125.                 goto ErrorExit;
  126.             }
  127.         }
  128.     }
  129.     
  130.     err = kGDXErrNoError;                                            // Everything okay.
  131.     
  132. ErrorExit:
  133.     return (err);
  134. }
  135.  
  136.  
  137.  
  138. //=====================================================================================================
  139. //
  140. // GraphicsUtilSetEntries()
  141. //    This is the meat of the code that changes the contents of the graphics hardware's CLUT.
  142. //
  143. //    This call has two flavors.  In the Sequence flavor, indicated by 'csStart >= 0', 'csCount' entries
  144. //    are changed in the CLUT, starting at 'csStart'  In this flavor, the 'value' field of the
  145. //    'ColorSpec' is ignored.
  146. //    In the Index flavor, indicated by 'csStart = -1', 'csCount' entries are installed into the CLUT at
  147. //    the address specified by their respective 'value' field of the 'ColorSpec' entry.
  148. //
  149. //    For this routine, the relevant fields indicated by 'VDSetEntryRecord' are:
  150. //            ->    csTable            pointer to array of 'ColorSpec'
  151. //            ->    csStart            (0 based) starting index, or -1.
  152. //                                If -1, then the 'value' field of each 'ColorSpec' entry indicates the
  153. //                                CLUT address to which the 'rgb' contents should be applied.
  154. //            ->    csCount            (0 based) number of 'ColorSpec' entries to set
  155. //
  156. //    The remaining parameters are described as follows:
  157. //
  158. //            -> gamma            Use this gamma table to apply gamma correction
  159. //            -> depthMode        The current relative pixel depth
  160. //            -> bitsPerPixel        The current absolute pixel depth
  161. //            -> luminanceMapping    'true' if luminanance mapping should occur
  162. //            -> directColor        'true' if in a direct color mode (16 or 32 bits/pixel)
  163. //
  164. //=====================================================================================================
  165. GDXErr GraphicsUtilSetEntries(const VDSetEntryRecord *setEntry, const GammaTbl *gamma, 
  166.         DepthMode depthMode, UInt32 bitsPerPixel, Boolean luminanceMapping, Boolean directColor)
  167. {
  168.     SInt16 startPosition;
  169.     SInt16 numberOfEntries;
  170.     Boolean sequential;
  171.  
  172.     SInt16 dataWidth;
  173.     UInt32 redIndex;
  174.     UInt32 greenIndex;
  175.     UInt32 blueIndex;
  176.     
  177.     UInt8 *redCorrection;                                    // Corrected red data in gamma
  178.     UInt8 *greenCorrection;                                    // Corrected green data in gamma
  179.     UInt8 *blueCorrection;                                    // Corrected blue data in gamma
  180.  
  181.     UInt32 i;                                                // Generic loop iterator
  182.     
  183.     GDXErr err = kGDXErrUnknownError;                        // Assume failure
  184.     
  185.     ColorSpec *originalCSTable = setEntry->csTable;
  186.     ColorSpec correctedCSTable[256];                        // Allocate array big enough for 8, 32 bpp
  187.         
  188.     // Make sure that 'setEntry' is pointing to a valid 'VDSetEntryRecord'
  189.     err = GraphicsUtilCheckSetEntry(setEntry, bitsPerPixel, &startPosition, &numberOfEntries, 
  190.             &sequential);
  191.     
  192.     if (err)
  193.         goto ErrorExit;
  194.  
  195.     // Make a copy of the client supplied 'originalCSTable' so luminance mapping (if applicable) 
  196.     // and gamma correction can take place without altering the original.
  197.  
  198.     for (i = startPosition ; i <= (startPosition + numberOfEntries) ; i++)
  199.     {
  200.         UInt32 j = i - startPosition;                    // 'originalCSTable' might not be 256 entries
  201.  
  202.         correctedCSTable[i].value = originalCSTable[j].value;
  203.         correctedCSTable[i].rgb.red = originalCSTable[j].rgb.red;
  204.         correctedCSTable[i].rgb.green = originalCSTable[j].rgb.green;
  205.         correctedCSTable[i].rgb.blue = originalCSTable[j].rgb.blue;
  206.     }
  207.     
  208.     // Check to see if luminance mapping should occur.  This should only happen if luminanceMapping
  209.     // is enabled and the device is NOT in a direct color mode.
  210.     if (luminanceMapping  && !directColor)
  211.     {
  212.         // Convert the RGB colors into luminance mapped gray scale.
  213.         // For those familiar with color space theory, 
  214.         //         
  215.         //        Luminance = .299Red + .587Green + .114Blue
  216.         //        ("Video Demystified" by Keith Jack, page 28)
  217.         //
  218.         // Conveniently, on the PowerPC architechture, floating point math is FASTER
  219.         // than integer math, so outright floating point will be done.
  220.         
  221.         double redPortion;                    // Luminance portion from red component
  222.         double greenPortion;                // Luminance portion from green component
  223.         double bluePortion;                    // Luminance portion from blue component
  224.         double luminance;                    // Resulting luminosity
  225.         
  226.         for (i = startPosition ; i <= (startPosition + numberOfEntries) ; i++)
  227.         {
  228.             UInt32 j = i-startPosition;                    // originalCSTable might not be 256 entries
  229.             
  230.             redPortion = 0.299 * originalCSTable[j].rgb.red;
  231.             greenPortion = 0.587 * originalCSTable[j].rgb.green;
  232.             bluePortion = 0.114 * originalCSTable[j].rgb.blue;
  233.             
  234.             luminance = redPortion + greenPortion + bluePortion;
  235.             
  236.             correctedCSTable[i].rgb.red = luminance;
  237.             correctedCSTable[i].rgb.green = luminance;
  238.             correctedCSTable[i].rgb.blue = luminance;
  239.             
  240.         }
  241.     }
  242.     
  243.     // Apply gamma correction to the 'correctedCSTable'
  244.     
  245.     dataWidth = gamma->gDataWidth;
  246.     redCorrection = (UInt8 *) &gamma->gFormulaData + gamma->gFormulaSize;
  247.     
  248.     if (1 == gamma->gChanCnt)
  249.     {
  250.         // Use same correction data for all three channels
  251.         greenCorrection = redCorrection;
  252.         blueCorrection = redCorrection;
  253.     }
  254.     else
  255.     {
  256.         // Each channel has its own correction data
  257.         greenCorrection = redCorrection + gamma->gDataCnt;
  258.         blueCorrection = redCorrection + ( 2 * gamma->gDataCnt);
  259.     }
  260.     
  261.     for (i = startPosition ; i <= (startPosition + numberOfEntries) ; i++)
  262.     {                                                                         
  263.         // Extract the most significant 'dataWidth' amount of bits from each color
  264.         // to use as the index into the correction data
  265.         
  266.         redIndex = correctedCSTable[i].rgb.red >> (16 - dataWidth);
  267.         greenIndex = correctedCSTable[i].rgb.green >> (16 - dataWidth);
  268.         blueIndex = correctedCSTable[i].rgb.blue >> (16 - dataWidth);
  269.         
  270.         correctedCSTable[i].rgb.red = *(redCorrection + redIndex);
  271.         correctedCSTable[i].rgb.green = *(greenCorrection + greenIndex);
  272.         correctedCSTable[i].rgb.blue = *(blueCorrection + blueIndex);
  273.     }
  274.     
  275.     // Now program the CLUT
  276.     
  277.     err = GraphicsHALSetCLUT(originalCSTable, correctedCSTable, startPosition, numberOfEntries,
  278.             sequential, depthMode);
  279.             
  280.     if (err)
  281.         goto ErrorExit;    
  282.     
  283.     err = kGDXErrNoError ;                                    // Everything Okay
  284.         
  285. ErrorExit:
  286.  
  287.     return (err);
  288. }
  289.  
  290.  
  291.  
  292. //=====================================================================================================
  293. //
  294. // GraphicsUtilBlackToWhiteRamp()
  295. //    When in direct color mode, it is sometimes necessary to build a black-to-white ramp in RGB, and
  296. //    apply it to the CLUT.
  297. //
  298. //    The will be accomplished by making a call to GraphicsUtilSetEntries().  First, a ramp will be built
  299. //    from black-to-white with an array of ColorSpecs.  For 16 bpp, the ramp will have 32 steps, and for
  300. //    32 bpp, the ramp will have 256.
  301. //
  302. //    The parameters are described as follows:
  303. //
  304. //            -> gamma            Use this gamma table to apply gamma correction
  305. //            -> depthMode        The current relative pixel depth
  306. //            -> bitsPerPixel        The current absolute pixel depth
  307. //            -> luminanceMapping    'true' if luminanance mapping should occur
  308. //            -> directColor        'true' if in a direct color mode (16 or 32 bits/pixel)
  309. //
  310. //=====================================================================================================
  311. GDXErr GraphicsUtilBlackToWhiteRamp(const GammaTbl *gamma, DepthMode depthMode,
  312.         UInt32 bitsPerPixel, Boolean luminanceMapping, Boolean directColor)
  313. {
  314.  
  315.     UInt16 i ;                                                // Loop control variable
  316.     UInt16 rampSteps ;                                        // # of steps to ramp from black to white 
  317.     UInt16 rampIncrement;                                    // Increment between ramp stamps
  318.     UInt16 rampValue ;
  319.     
  320.     VDSetEntryRecord setEntry;                                // To make GraphicsUtilSetEntries() call
  321.  
  322.     GDXErr err = kGDXErrUnknownError;                        // Assume failure
  323.     ColorSpec rgbRampCSTable[256];                            // 16 bpp = 32 ColorSpecs. 8, 32 bpp = 256
  324.     
  325.     if (16 == bitsPerPixel)
  326.         rampSteps = 32;                        // 16 bpp -- ramp from black-to-white in 32 steps
  327.     else
  328.         rampSteps = 256;                    // 32 bpp -- ramp from black-to-white in 256 steps
  329.  
  330.     
  331.     // Build the black-to-white ramp in the ColorSpec array.  ColorSpecs represent the red,
  332.     // green, and blue components of a RGB color as unsigned 16 bit numbers.  Gamma tables only 
  333.     // use the most significant gDataWidth # of bits of an RGB component, where gDataWidth <= 8.
  334.     // Therefore, an adequate black-to-white ramp can be created by having the most significant
  335.     // byte of each RGB component range from 0 - 255 in 'rampSteps' number of steps.
  336.     
  337.     rampIncrement = 256 / rampSteps;                // Increment between ramp steps
  338.     rampValue = 0;                                    // Start ramp at 0
  339.     
  340.     for (i = 0 ; i < rampSteps ; i++)
  341.     {
  342.         rgbRampCSTable[i].rgb.red = rampValue << 8;        // Set the most significant byte to 'rampValue'
  343.         rgbRampCSTable[i].rgb.green = rampValue << 8;    //  "   "    "       "        "   "      "
  344.         rgbRampCSTable[i].rgb.blue = rampValue << 8;    //  "   "    "       "        "   "      "
  345.         rampValue += rampIncrement;                        // Increment the value for the next step
  346.     }
  347.  
  348.     // Apply the black-to-white ramp to the hardware.  This can be done by calling 
  349.     // GraphicsCoreDirectSetEntries(), so set up a 'VDSetEntryRecord' for the call.
  350.     
  351.     setEntry.csTable = rgbRampCSTable;                
  352.     setEntry.csStart = 0;                                // Start with index 0 of the ColorSpec array
  353.     setEntry.csCount = rampSteps - 1;                    // -1 since csCount is 0 based.
  354.     
  355.     // Apply the gamma corrected ramp to hardware
  356.     err = GraphicsUtilSetEntries(&setEntry, gamma, depthMode, bitsPerPixel, luminanceMapping,
  357.             directColor);
  358.             
  359.     if (err)
  360.         goto ErrorExit;
  361.         
  362.     err = kGDXErrNoError ;                                    // Everything Okay
  363.  
  364. ErrorExit:
  365.  
  366.     return (err);
  367. }
  368.  
  369.  
  370.  
  371. //=====================================================================================================
  372. //
  373. // GraphicsUtilGetDefaultGammaTableID()
  374. //    This routine returns the default gamma table for the specified DisplayCode.  This is provided so
  375. //    the driver can apply a proper gamma table during the boot sequence, prior to the DisplayMgr setting
  376. //    the preferred one.
  377. //
  378. //        ->    displayCode        Specifier of the display in question
  379. //        <-    gammaTableID    Specifier of the default gamma table for the given display.            
  380. //
  381. //
  382. //=====================================================================================================
  383. GDXErr GraphicsUtilGetDefaultGammaTableID(DisplayCode displayCode, GammaTableID *gammaTableID)
  384. {        
  385.     switch (displayCode)
  386.     {
  387.         case kDisplayCode12Inch :
  388.             *gammaTableID = kGammaTableIDRubik;
  389.             break;
  390.             
  391.         case kDisplayCodePortraitMono :    
  392.         case kDisplayCode21InchMono :
  393.             *gammaTableID = kGammaTableIDGray;
  394.             break;
  395.             
  396.         case kDisplayCodeNTSC :    
  397.         case kDisplayCodePAL :
  398.             *gammaTableID = kGammaTableIDNTSCPAL;
  399.             break;
  400.             
  401.         case kDisplayCodeUnknown :
  402.         case kDisplayCodeStandard :  
  403.         case kDisplayCodeVGA :
  404.         case kDisplayCodePortrait :    
  405.         case kDisplayCode16Inch :
  406.         case kDisplayCode19Inch :    
  407.         case kDisplayCode21Inch :
  408.         case kDisplayCodeMultiScanBand1 :
  409.         case kDisplayCodeMultiScanBand2 :
  410.         case kDisplayCodeMultiScanBand3 :
  411.             *gammaTableID = kGammaTableIDStandard;    
  412.             break;
  413.             
  414.         default:
  415.             *gammaTableID = kGammaTableIDStandard;    
  416.     }
  417.     
  418.     return (kGDXErrNoError);
  419. }
  420.  
  421.  
  422.  
  423. //=====================================================================================================
  424. //
  425. // GraphicsUtilMapSenseCodesToDisplayCode()
  426. //    This routine will map RawSenseCode/ExtendendSenseCode pairs to their corresponding DisplayCode
  427. //    for frame buffer controllers which either have 'standard' sense code hardware (or...can coerce
  428. //    their raw/extended sense codes to appear standard).
  429. //
  430. //    This functionality is provided as a utility routine in the Core, because a large number of
  431. //    frame buffer controllers have support for 'standard' sensing.
  432. //
  433. //    The parameters are described as follows:
  434. //
  435. //            -> rawSenseCode            Result from reading sense lines
  436. //            -> extendedSenseCode    Result from applying extended sense algorithm to sense lines
  437. //            <- displayCode            DisplayCode which the RawSenseCode/ExtendedSenseCode map to.
  438. //
  439. //=====================================================================================================
  440. GDXErr GraphicsUtilMapSenseCodesToDisplayCode(RawSenseCode rawSenseCode,
  441.         ExtendedSenseCode extendedSenseCode, DisplayCode *displayCode)
  442. {
  443.  
  444.     GDXErr err = kGDXErrNoError;                    // Assume success
  445.     UInt32 i;                                        // Loop control variable
  446.     
  447.     // Define a type which maps a RawSenseCode/ExtendedSenseCode pair to its corresponding DisplayCode.
  448.     // This type is defined locally since nothing outside the scope of this function needs to 
  449.     // be aware of it.
  450.     
  451.     typedef struct SenseCodesToDisplayCodeMap SenseCodesToDisplayCodeMap;
  452.     struct SenseCodesToDisplayCodeMap
  453.     {
  454.         RawSenseCode rawSenseCode;
  455.         ExtendedSenseCode extendedSenseCode;
  456.         DisplayCode displayCode;
  457.     };
  458.     
  459.     
  460.     enum { kMapSize = 19 };
  461.     
  462.     SenseCodesToDisplayCodeMap map[kMapSize] =
  463.     {
  464.         {kRSCZero,    kESCZero21Inch,                kDisplayCode21Inch},
  465.         
  466.         {kRSCOne,    kESCOnePortraitMono,        kDisplayCodePortraitMono},
  467.  
  468.         {kRSCTwo,    kESCTwo12Inch,                kDisplayCode12Inch},
  469.         
  470.         {kRSCThree,    kESCThree21InchRadius,        kDisplayCode21Inch},
  471.         {kRSCThree,    kESCThree21InchMonoRadius,    kDisplayCode21InchMono},
  472.         {kRSCThree,    kESCThree21InchMono,        kDisplayCode21InchMono},
  473.                 
  474.         {kRSCFour,    kESCFourNTSC,                kDisplayCodeNTSC},
  475.         
  476.         {kRSCFive,    kESCFivePortrait,            kDisplayCodePortrait},
  477.         
  478.         {kRSCSix,    kESCSixMSB1,                kDisplayCodeMultiScanBand1},
  479.         {kRSCSix,    kESCSixMSB2,                 kDisplayCodeMultiScanBand2},
  480.         {kRSCSix,    kESCSixMSB3,                kDisplayCodeMultiScanBand3},
  481.         {kRSCSix,    kESCSixStandard,            kDisplayCodeStandard},
  482.     
  483.         {kRSCSeven,    kESCSevenPAL,                kDisplayCodePAL},
  484.         {kRSCSeven, kESCSevenNTSC,                kDisplayCodeNTSC},
  485.         {kRSCSeven, kESCSevenVGA,                kDisplayCodeVGA},
  486.         {kRSCSeven, kESCSeven16Inch,            kDisplayCode16Inch},
  487.         {kRSCSeven, kESCSevenPALAlternate,        kDisplayCodePAL},
  488.         {kRSCSeven, kESCSeven19Inch,             kDisplayCode19Inch},
  489.         {kRSCSeven, kESCSevenNoDisplay,         kDisplayCodeNoDisplay},
  490.     };
  491.  
  492.     
  493.     *displayCode = kDisplayCodeUnknown;        // Assume unknown type of display attached
  494.     
  495.     for (i = 0 ; i < kMapSize ; i++)
  496.     {
  497.         if ((map[i].rawSenseCode == rawSenseCode) && (map[i].extendedSenseCode == extendedSenseCode))
  498.         {
  499.             *displayCode = map[i].displayCode;
  500.             break;
  501.         }
  502.     }
  503.     
  504.     return (err);
  505. }
  506.  
  507.