home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-07-05 | 79.1 KB | 2,112 lines | [TEXT/CWIE] |
- /*
- GDVideo.c
- Copyright © 1989-1996 Denis G. Pelli
-
- Complete set of routines to control video drivers directly, bypassing
- QuickDraw's Color and Palette Managers. There is a separate function call for
- each of the Control and Status Calls (csc) implemented by video drivers. They
- are described in Designing Cards and Drivers, 3rd Ed., chapter 9. A few new
- calls are documented in the Display Device Driver Guide Developer Note, which
- appeared on the January '94 Developer CD.
-
- This file also contains several other helpful routines that deal with video
- device drivers. For background, read “Video synch”.
-
- GDSetEntries
-
- The most useful routine in this file is GDSetEntries. It implements a cscSetEntries Control
- call to the video driver. This directly sets the video device's color lookup table (clut).
- (cscSetEntries is documented in Apple's books called
- Designing Cards and Drivers and Designing PCI Cards and Drivers.)
-
- Apple also provides a high-level SetEntries() call, which is superficially similar,
- but it gets interpreted by QuickDraw in complicated ways before ultimately
- causing a cscSetEntries Control call to the video driver.
- (SetEntries is documented in Inside Macintosh.)
-
- I always prefer GDSetEntries, because I want direct control over the clut.
-
- THE MORE-USEFUL (HIGH-LEVEL) ROUTINES: (in alphabetical order)
-
- char *GDCardName(GDHandle device);
- Returns the address of a C string containing the name of the video card. You
- should call DisposePtr() on the returned string when you no longer need it.
- Takes about 1.5 ms because Apple's slot routines are very slow.
-
- short GDClutSize(GDHandle device);
- Returns the number of entries in the video driver's clut in the current video
- mode (i.e. current pixel size). VideoToolbox.h defines a preprocessor macro
- GDCLUTSIZE(device) that expands to equivalent inline code.
-
- long GDColors(GDHandle device)
- Number of colors, in the current mode.
-
- short GDDacSize(GDHandle device)
- Figures out how many bits in the video dac.
-
- OSErr GDSetDelay(GDHandle device,Boolean dontWaitForVBL,double nanoseconds);
- OSErr GDGetDelay(GDHandle device,Boolean *dontWaitForVBLPtr,double *nanosecondsPtr);
- These two routines support features, i.e. cscSetTimeDelays and cscGetTimeDelays,
- unique to the built-in video driver of the
- PowerMac 7500 and 8500. Both routines will merely return innocuous errors (-17
- and -18) if used with any other video driver. Like most video drivers, the
- 7500/8500 video driver normally waits for VBL when loading the CLUT, but this can
- be overriden by the Boolean parameter dontWaitForVBL, in which case, from then on
- (until it's changed again or the machine is rebooted) the driver will load the
- CLUT immediately when it's called, without waiting for VBL. The second feature is
- that the video driver normally waits 800 ns after loading each RGB triplet to the
- CLUT, "to allow for the CLUT to settle and increment its address", and that time
- can be set by the parameter "nanoseconds". GDGetDelay() allows you to read the
- current setting of both parameters. GDSetDelay() allows you to set both
- parameters. If the supplied value of "nanoseconds" is infinite or NAN then it's
- ignored and only "dontWaitForVBL" is set. The 7500/8500 video driver was written
- by Apple Engineer Fernando Urbina, nano@apple.com. GDSetDelay() and GDSetDelay()
- were written by Denis Pelli, to allow convenient access to Fernando's custom
- control and status driver calls. Note that Fernando Urbina has also supplied a
- newer version of this driver (included in the VideoToolbox) that supports several
- extra resolutions, of which the most noteworthy is 640x480x120 Hz, which works
- well on the Apple 17" Multiscan.
-
- Thus far, using visual inspection in TimeVideo, I've been unable to notice any
- bad effects of not waiting for VBL and reducing the waiting interval from 800 ns
- to zero. I asked Fernando Urbina, nano@apple.com, about it, since he put in the
- delays because he "does indeed get artifacts when updating the CLUT if we don't
- suppress interrupts while updating it." What were the artifacts? Fernando
- replies, "The delays are there because of hardware requirements: When writing to
- the CLUT in a self-incrementing mode the hardware requires 800ns to update the
- address counter. Of course, this is worst case. ( We write the CLUT starting
- address and then the R, G, and B. At the end of the B, the address counter for
- the CLUT will automatically increment to the next address.) I noticed some
- artifacts when doing palette animation -- one of the After Dark modules showed
- this very well."
-
- OSErr GDGetDisplayMode(GDHandle device,unsigned long *displayModeIDPtr
- ,unsigned short *modePtr,unsigned short *pagePtr,Ptr *baseAddrPtr);
- Calls cscGetCurMode, documented in Apple's new Display Device Driver Guide
- Developer Note on the January '94 Developer CD. The "display mode ID" is a new
- parameter, to support multi-resolution displays. Each display mode may have
- multiple pixel depths (which, confusingly, have also been called "modes"). This
- call will only be useful if the Display Manager is present (requires PowerPC or
- System 7.5) and if you're using the Display Manager, which is documented in a
- chapter in Inside Macintosh:Advanced Color Imaging, which thus far has appeared
- only in draft form on the December '94 Developer CD. The call returns an error
- if the video driver does not support the Display Manager. UNTESTED!!
-
- OSErr GDGetEntries(GDHandle device,short start,short count,ColorSpec *table);
- Calls cscGetEntries. This is much as you'd expect after reading GDSetEntries
- below, EXCEPT that cscGetEntries writes into table[start],....
- whereas cscSetEntries reads from table[0],....
- Note that unless the gamma table is linear, the values returned may not
- be the same as those originally passed by GDSetEntries. So call
- GDUncorrectedGamma first. Try the demo TimeVideo.
-
- OSErr GDGetGamma(GDHandle device,GammaTbl **myGammaTblHandle);
- Calls cscGetGamma. Returns a pointer to the Gamma table in the specified video
- device. (I.e. you pass it a pointer to your pointer, a handle, which it uses to
- load your pointer.)
-
- OSErr GDGetPageCnt(GDHandle device,short mode,short *pagesPtr);
- Calls cscGetPageCnt. Called "GetPages" in Designing Cards and Drivers, 3rd Ed.
- You tell it which mode you're interested in. It tells you how many pages of
- video ram are available in that mode.
-
- Boolean GDHasMode(GDHandle device,short mode,short *pixelSizePtr,short *pagesPtr);
- Returns 0 if no such video mode, returns 1 if mode is available.
- If pixelSizePtr is not NULL, then sets *pixelSizePtr to pixelSize or -1 if unknown.
- If pagesPtr is not NULL, then sets *pagesPtr to pages.
-
- unsigned char *GDName(GDHandle device);
- Returns a pointer to the name of the driver (a pascal string). This is quick.
- The string is part of the driver itself, so don't modify it or try to dispose of it.
-
- unsigned char *GDNameStr(GDHandle device);
- Returns a pointer to the name of the driver, as a C string.
- The string is static, and will be overwritten by the next call to GDNameStr().
-
- ColorSpec *GDNewLinearColorTable(GDHandle device);
- Creates a default table for use when gdType==directType.
-
- OSErr GDPrintGammaTable(FILE *o,GDHandle device);
-
- OSErr GDRestoreDeviceClut(GDHandle device);
- Nominally equivalent to Apple's RestoreDeviceClut(), which is only available
- since System 6.05. However, I find that Apple's routine sometimes does nothing,
- whereas this routine always works. Passing a NULL argument causes restoration of
- cluts of all video devices.
-
- OSErr GDSaveGamma(GDHandle device);
- OSErr GDRestoreGamma(GDHandle device);
- Use an internal cache to save and restore the device's gamma-correction table.
- GDSaveGamma(NULL) and GDRestoreGamma(NULL) save and restore ALL devices.
- After the first request, GDSaveGamma() ignores subsequent requests to save the same
- device's gamma table. GDRestoreGamma() no longer discards the saved copy (the cache), so multiple
- calls to GDRestoreGamma() will all be effective. You should call
- GDRestoreGamma before GDRestoreDeviceClut, because the video driver merely saves the gamma
- table when you do a cscSetGamma; the driver actually uses the gamma table to transform
- a new clut only when loading the clut.
-
- OSErr GDSetEntries(GDHandle device,short start,short count,ColorSpec *table);
- Does a cscSetEntries call to the video card's driver, loading any
- number of clut entries with arbitrary rgb triplets. (Note that the driver will
- transform your rgb triplets via the gamma table before loading them into the
- clut; so call GDUncorrectedGamma first.) "device" specifies which video device's
- clut you want to load. "start" is either in the range 0 to clutSize-1,
- indicating which clut entry to load first (in "sequence mode"), or is -1
- (requesting "index mode"). "count" is the number of entries to be modified,
- minus 1. "table" is a ColorSpec array (not a ColorTable) containing the rgb
- triplets that you want to load into the clut. In sequence mode "start" must be
- in the range 0 to clutSize-1, the i-th element of table corresponds to the
- i-th entry in the clut, and the "value" field of each element of table is
- ignored. In index mode "start" must be -1, and the "value" field of each element
- of table indicates which clut entry to load it into. The arguments start, count,
- and (perhaps) table are the same as for the Color Manager call SetEntries(), documented in
- Inside Macintosh V-143. Note that cscSetEntries reads from table[0],....
- whereas cscGetEntries writes to table[start],....
- (Most drivers wait for blanking before modifying the
- clut. For a full discussion, read the VideoToolbox "Video synch" file.) You may
- also want to look at the file SetEntriesQuickly.c, which provides the
- functionality of GDSetEntries and GDDirectSetEntries, but bypasses the video
- driver to access the hardware directly.
-
- OSErr GDSetEntriesByType(GDHandle device,short start,short count,ColorSpec *table);
- Checks the (**device).gdType field and calls cscSetEntries, cscDirectSetEntries,
- or nothing, as appropriate.
-
- OSErr GDSetEntriesByTypeHighPriority(GDHandle device,short start,short count
- ,ColorSpec *table);
- Calls GDSetEntriesByType() while the processor priority has been temporarily
- raised to 7.
-
- OSErr GDSetGamma(GDHandle device, GammaTbl *gamma);
- Calls cscSetGamma. Loads a Gamma table into the specified video device. The
- video driver will make a copy of your table. You can discard your table after
- making this call. Note that the video driver only uses the gamma table when
- performing cscSetEntries, i.e. when actually loading the clut. The structure of the
- gamma table is (finally!) documented in Designing Cards and Drivers, 3rd
- edition, pages 215-216. Beware of a discrepancy between the documentation and
- the definition in QuickDraw.h: gFormulaData is described as a byte array in the
- text, but is declared as a short array in the QuickDraw.h header file. NOTE: a
- few video drivers (Radius PowerView and SuperMac ColorCard) do not support gamma
- tables. The SuperMac ColorCard is well behaved, giving the appropriate error
- code, returned by GDSetGamma and GDGetGamma. The Radius PowerView reports no
- error yet ignores the GDSetGamma call and returns a table full of zeroes in
- response to GDGetGamma. See NOTE from Tom Busey below. However, if all you want
- to do is call GDUncorrectedGamma, then these limitations won't affect you,
- because the drivers that lack gamma tables always give you precisely the
- behavior that one requests by calling GDUncorrectedGamma.
-
- OSErr GDSetPageDrawn(GDHandle device,short page);
- Choose which page of video memory will be used by future drawing operations.
- Untested.
-
- OSErr GDSetPageShown(GDHandle device,short page);
- Choose which page of video memory we see. Untested.
-
- OSErr GDUncorrectedGamma(GDHandle device);
- Asks GDSetGamma to load a linear gamma table, i.e. no correction. (The gamma
- correction implemented by table-lookup in the video driver is too crude for
- experiments that want accurate luminance control.)
-
- int GDVersion(GDHandle device)
- Returns the version number of the driver. From the first word-aligned word after
- the name string. This is quick.
-
- OSErr GDGetNextResolution()
- Implements cscGetNextResolution.
-
- LESS-USEFUL (LOW LEVEL) ROUTINES:
-
- OSErr GDControl(int refNum,int csCode,Ptr csParamPtr)
- Uses low-level PBControl() call to implement a "Control()" call that works!
- I don't know why this wasn't discussed in Apple Tech Note 262.
-
- OSErr GDDirectSetEntries(GDHandle device,short start,short count,ColorSpec *table);
- Calls cscDirectSetEntries. If your pixel depth is >8 then the cscSetEntries call is
- disabled, and you must use this instead of GDSetEntries().
-
- VideoDriver *GDDriverAddress(GDHandle device);
- Returns a pointer to the driver, whether in ROM or RAM. Neither this prototype
- nor the definition of the VideoDriver structure are included in VideoToolbox.h.
-
- OSErr GDGetDefaultMode(GDHandle device,short *modePtr)
- Calls cscGetDefaultMode. It tells you what the default mode is. I'm not sure
- what this means.
-
- OSErr GDGetGray(GDHandle device,Boolean *flagPtr);
- Calls cscGetGray. Get gray flag. 0 for color. 1 if all colors mapped to
- luminance-equivalent gray tones.
-
- OSErr GDGetInterrupt(GDHandle device,Boolean *flagPtr);
- Calls cscGetInterrupt. Get flag. 1 if VBL interrupts of this card are enabled. 0
- if disabled.
-
- OSErr GDGetMode(GDHandle device,short *modePtr,short *pagePtr,Ptr *baseAddrPtr);
- Calls cscGetMode. It tells you the current mode, page of video memory, and the
- base address of that page.
-
- OSErr GDGetPageBase(GDHandle device,short page,Ptr *baseAddrPtr);
- Calls cscGetPageBase. (Called "cscGetBaseAddr" in Designing Cards and Drivers, 3rd
- Ed.) You tell it which page of video memory you're interested in (in the current
- video mode). It tells you the base address of that page.
-
- OSErr GDGrayPage(GDHandle device,short page);
- Calls cscGrayPage. (Called "cscGrayScreen" in Designing Cards and Drivers, 3rd
- Ed.) Fills the specified page with gray, i.e. the dithered desktop pattern. I'm
- not aware of any particular advantage in using this instead of FillRect().
- Designing Cards and Drivers, 3rd Edition, Chapter 9, says that for direct
- devices, i.e. >8 bit pixels, the driver will also load a linear,
- gamma-corrected, gray color table.
-
- OSErr GDReset(GDHandle device, short *modePtr, short *pagePtr, Ptr *baseAddrPtr);
- Calls cscReset. Initialize the video card to its startup state, usually 1 bit
- per pixel. Returns the parameters of that state.
-
- OSErr GDSetDefaultMode(GDHandle device,short mode);
- Calls cscSetDefault. Supposedly, you tell it what mode you want to start up with
- when you reboot. (I've never been able to get this to work. No error and no
- effect. Perhaps I've misunderstood its purpose.)
-
- OSErr GDSetGray(GDHandle device,Boolean flag);
- Calls cscSetGray. Set gray flag. 0 for color. 1 if all colors mapped to
- luminance-equivalent gray tones.
-
- OSErr GDSetInterrupt(GDHandle device,Boolean flag);
- Calls cscSetInterrupt. Set flag to 1 to enable VBL interrupts of this card, or 0
- to disable.
-
- OSErr GDSetMode(GDHandle device,short mode,short page,Ptr *baseAddrPtr);
- Calls cscSetMode. You tell it what mode and video page you want. It sets 'em and
- returns the base address of that page in video memory. Also, because Apple said
- so, the video driver sets the entire clut to 50% gray. Note that this changes
- things behind QuickDraw's back. For most applications life will be simpler if
- you overtly ask QuickDraw to take charge by calling Apple's SetDepth() instead
- of GDSetMode(). WARNING: Apple now considers the mode numbers merely ordinal.
- E.g. on the 8•24 video card the 32-bit mode has mode number 0x84, not 0x85 as
- you might have expected on the basis of old Apple documentation and other Apple
- video cards.
-
- OSErr GDSwitchMode(GDHandle device,short mode,long displayModeID,short page,Ptr *baseAddrPtr);
- Calls cscSwitchMode as documented in Designing PCI Video Cards and Drivers. PCI
- video drivers are required to support this call. It's like GDSetMode, but additionally
- allows you to specify the displayModeID, which determines the spatial resolution.
-
- OSErr GDStatus(int refNum,int csCode,Ptr csParamPtr)
- Uses low-level PBStatus() call to implement a "Status()" call that works! The
- need for this is explained in Apple Tech Note 262, which was issued in response
- to my bug report in summer of '89.
-
- PatchMacIIciVideoDriver();
- Fixes a crashing bug in the Mac IIci built-in video driver's implementation of
- cscGetEntries. The patch persists until reboot. It is unlikely that you will need
- to call this explicitly, PatchMacIIciVideoDriver() is automatically invoked the
- first time GDGetEntries is called. The Mac IIci built-in video driver
- (.Display_Video_Apple_RBV1 driver, version 0) has a bug that causes it to crash
- if you try to do a cscGetEntries Status request. PatchMacIIciVideoDriver() finds and
- patches the copy of the buggy driver residing in memory. (If the driver is
- ROM-based it first moves it to RAM, and then patches that.) Only two instructions
- are modified, to save & restore more registers. This fix persists only until the
- next reboot. If the patch is successfully applied the version number is increased
- by 100.
-
- NOTES:
-
- Several bugs in version 2 (in System ≤6.03) of the video driver for Apple's
- "Toby Frame Buffer" video card that affected use of the GetGamma call were
- fixed in version 3 (in System 6.04), apparently in response to my bug report to
- Apple.
-
- The control/status-call parameter in a GDControl or GDStatus call specifies what
- you want done. See Designing Cards and Drivers, 3rd Edition, Chapter 9. (A few
- new calls are documented in the Display Device Driver Guide Developer Note.)
- Note that sometime around 1990 Apple renamed some of the Control and Status
- calls, giving them names that better reflect their function. I followed suit.
- However, Apple neglected to update their book, Designing Cards and Drivers, now
- in its 3rd edition. Fortunately, they define both names in their Video.h header
- file. To avoid confusion, here are the equivalences. Note that "csc" stands for
- "Control and Status Call"
- Control call:
- cscGrayPage = cscGrayScreen = 5
- Status calls:
- cscGetPageCnt = cscGetPages = 4
- cscGetPageBase = cscGetBaseAddr = 5
-
- Based on:
- Inside Macintosh-II (Device Manager)
- Designing Cards and Drivers, 3rd Edition, Chapter 9.
- Display Device Driver Guide Developer Note on the January '94 Developer CD.
- Tech Note 262: "Controlling Status Calls"
- "GreyScale Information" from AppleLink "Apple Technical Info"
- "Video Configuration ROM Software Specification" also from AppleLink,
- in "Developer Tech Support:Macintosh:32 Bit QuickDraw"
-
- NOTES:
- Tom Busey (busey@indiana.edu) writes: "I'm using an 8-bit SuperMac ColorCard
- that a used computer dealer gave me when I ordered a Toby card. I discovered
- that the status and control calls for GDUncorrectedGamma return -17 and -18
- respectively, which means that the driver doesn't support different gammas.
- GDUncorrectedGamma returns an error message, but GDOpenWindow doesn't use the
- error message or pass it back to the calling program. I'm wondering if there are
- people using GDOpenWindow who think that they are getting a linear gamma but who
- are actually getting an error message and not learning about it."
- Tom's facts are right, but he needn't worry. A few video drivers, e.g.
- Radius PowerView, and apparently the SuperMac ColorCard, don't implement gamma
- tables at all, but the error from GDUncorrectedGamma is probably not a concern.
- The real test is to run TimeVideo. TimeVideo does a write-and-read-back test of
- the clut of your video card. If that test passes then you can safely conclude
- that there's no gamma translation going on. So, as nearly every document in the
- VideoToolbox says: run TimeVideo and read the report.
- Here's how gamma tables work. According to the Apple manual (Designing
- Cards and Drivers), the values in the rgb triplets that you supply in a
- cscSetEntries call to the video driver are first translated via the gamma table
- (each r,g, and b component separately) before being loaded into the CLUT
- hardware table. Most drivers maintain a gamma table internally (in computer
- memory) and allow you to get and set it via the cscGetGamma and cscSetGamma
- calls. A few video drivers (Radius PowerView, SuperMac ColorCard) don't support
- gamma tables. They load your rgb values directly into the CLUT, without
- translation. However, for users of the VideoToolbox that's usually fine, since
- that's exactly the behavior that we routinely request by calling
- GDUncorrectedGamma. Of course, if you want to load a custom gamma table, other
- than the identity transformation, then you'll be calling GDSetGamma, and you
- should make sure it does not return an error. (Alas, the Radius PowerView driver
- more or less ignores the cscSetGamma and cscGetGamma requests--GDGetGamma
- returns a table that's all zeroes--but the driver fails to report an error. I
- wrote to the Radius programmer a year ago, but they're no longer interested in
- working on that product.)
- Patrick Flanagan (flanagan@deakin.edu.au) writes: "Can I be 100% sure, if I
- select "Special Gamma", in the Monitors Control Panel and choose "uncorrected
- gamma" for a video card, that this is the same as using GDUncorrectedGamma?"
- REPLY: That is what I would expect from reading all the relevant documentation.
- However, to be 100% certain of anything I would want to check it myself.
- TimeVideo calls GDUncorrectedGamma and then confirms that write-then-read tests
- of the CLUT return what was written. (Gamma-table translation is only done on
- the write, not undone on the read.) Thus TimeVideo will confirm for you that
- after calling GDUncorrectedGamma your video card has what Apple calls an
- "uncorrected" gamma table. However, TimeVideo does not check what you would get
- by merely selecting "uncorrected" gamma in the Monitors Control Panel. It would
- be reasonable to assume that you would get the same result since Monitors
- interacts with the video driver by the same Control and Status Calls as
- GDVideo.c does, so it must use the same cscSetGamma call as is used by
- GDUncorrectedGamma.
-
- HISTORY:
- 9/29/89 dgp added caution above that successive calls to cscSetEntries may be on one
- frame.
- 11/21/89 dgp corrected mode list: 0x80... as pointed out by Chuck Stein
- 11/30/89 dgp added note above from Don Kelly.
- Added cautionary note above about GDSetEntries().
- 3/1/90 dgp updated comments.
- 3/3/90 dgp included Video.h instead of defining VDSetEntryRecord and VDPageInfo.
- 3/20/90 dgp made compatible with MPW C.
- 3/23/90 dgp changed char to unsigned char in VDDefModeRec
- and VDFlagRec to prevent undesirable sign extension.
- 4/2/90 dgp Deleted mode argument from GDGrayScreen().
- 7/28/90 dgp Fixed stack overflow in GDGrayScreen, by declaring SysEnvRec static.
- 10/20/90 dgp Apple has renamed the control and status calls, so I followed suit:
- •GDGetPageBase replaces GDGetBaseAddr
- •GDReset replaces GDInit
- •GDGrayPage replace GDGrayScreen
- •GDGetPageCnt replaces GDGetPages
- 2/12/91 dgp Discovered that the old bug in GDGrayPage is still present in System
- 6.05, so I removed the conditional around the bug fix. TestGDVideo
- now works with: Mac II Video Card, Mac II Display Card (4•8),
- Mac IIci Built-in Video, TrueVision NuVista, Mac IIsi Built-in Video.
- 7/22/91 dgp Changed definition of csGTable from GammaTblPtr to Ptr,
- to conform with MPW C.
- 8/24/91 dgp Made compatible with THINK C 5.0.
- 10/22/91 dgp With help from Bart Farell, converted all functions headers to
- Standard C style.
- 8/26/92 dgp added a few miscellaneous comments
- In all routines, *baseAddrPtr is now set only if baseAddrPtr is not NULL.
- 10/10/92 dgp Added GDRestoreDeviceClut(). Removed obsolete support for THINK C 4.
- 11/30/92 dgp corrected error in comment documenting values of argument to GDSetGray().
- Set flag to zero for color,1 for luminance-mapped gray.
- 12/9/92 dgp Enhanced GDRestoreDeviceClut(). Passing a NULL argument now requests
- application to all devices. I only just learned that Apple's
- RestoreDeviceClut() behaves in this way.
- 12/15/92 dgp Renamed GDRestoreDeviceClut to GDRestoreDeviceClut to be consistent
- with Apple's capitalization of RestoreDeviceClut.
- 12/16/92 dgp Updated comments to be consistent with 3rd edition of Designing Cards
- and Drivers. •Renamed myGDHandle to "device", which is easier to read.
- Renamed GDLinearGamma to GDUncorrectedGamma, and generalized it
- to work with any size DAC. For compatibility with old programs
- VideoToolbox.h now has a #define statement making GDLinearGamma
- an alias for GDUncorrectedGamma.
- 12/30/92 dgp Updated some of the comments. Eliminated Files.h.
- 12/30/92 dgp Use GDClutSize() to determine clut size.
- 1/4/93 dgp In GDClutSize, check for fixedType.
- 1/5/93 dgp In GDClutSize, only set last clut entry.
- Added PatchMacIIciVideoDriver() to the end of this file, and
- automatically invoke it the first time GDGetEntries is called.
- 1/6/93 dgp Cleaned up GDClutSize. It now seems to work correctly in the direct modes.
- 1/18/93 dgp Spruced up the documentation.
- •Added all the code formerly in GDIdentify.c, but omitted the obsolete
- function GDIdentify(), which simply printed GDName() and GDVersion.
- •Enhanced GDGetEntries() to avoid calling drivers that are known
- to crash, returning a statusErr instead.
- •Recoded PatchMacIIciVideoDriver() so as not to call GetScreenDevice.c.
- 2/1/93 dgp Fixed endless loop in PatchMacIIciVideoDriver. Enhanced to deal with
- ROM-based drivers as well.
- 2/5/93 dgp Expanded the documentation of GDSetEntries above, and supplied sample
- code showing how to load the clut.
- 2/7/93 dgp Fixed endless loop in PatchMacIIciVideoDriver.
- 2/20/93 dgp Fixed bug in GDUncorrectedGamma() that was causing TestCluts to fail
- for video devices that have nonstandard gamma tables.
- 3/18/93 dgp Fixed divide by zero error in GDClutSize.
- 4/6/93 dgp GDGetPageCnt() now sets *pagePtr argument only if no error occurs.
- Deleted GDModeName(). Removed assumption, in all routines, that there
- is any particular correspondence between the video mode number and
- the pixel size. Added two new routines, GDPixelSize and GDType,
- that return the pixelSize and gdType (i.e. fixedType, clutType, or
- directType) of the device. Completely rewrote GDClutSize.
- 4/16/93 dgp Streamlined GDClutSize() to make it fast enough for routine use.
- 4/19/93 dgp Added GDNewLinearColorTable.
- 4/25/93 dgp Made CntrlParam automatic instead of static.
- 4/25/93 dgp Added GDColors(device) and GDPrintGammaTable(). Alphabetized the lists
- of functions in the documentation above.
- 5/11/93 dgp Changed GDPrintGammaTable() to accept a simple file pointer instead of
- an array of two file pointers.
- 7/7/93 dgp enhanced GDDacSize() to return 8 unless the gamma table is present and
- reasonable.
- 7/29/94 dgp added GDNameStr().
- 9/5/94 dgp removed assumption in printf's that int==short.
- 10/25/94 dgp check for missing driver, (*device)->gdRefNum==0, and treat that case
- just like device==NULL. Devices created by NewGWorld have no driver.
- 12/29/94 dgp added GDGetDisplayMode(), calls cscGetCurMode, based on Apple's new
- Display Device Driver Guide Developer Note on the January '94 Developer CD.
- 1/15/94 dgp GDPixelSize if supplied with a merely device record, with no associated
- device driver, then we just return (**(**device).gdPMap).pixelSize
- 3/22/95 dgp Added .Display_Video_Apple_DOMEMax to the list of drivers that don't
- support cscGetEntries. Crash reported by Greg Jackson.
- 4/6/95 dgp Changed GDUncorrectedGamma() to pass a NULL gamma table pointer instead of
- a linear gamma table, in the hopes that this might work even with the
- few video drivers that don't fully support cscSetGamma.
- 4/21/95 dgp Fixed conditionals to cope with various versions of Video.h
- 6/8/95 dgp Made sure that the Mac structs are always 68k aligned.
- 6/26/95 dgp fixed error in dealing with UNIVERSAL_HEADERS==1 reported by Bart Farell.
- We need the typedefs for DisplayModeID and DepthMode for universal headers
- absent and also for version 1.
- 6/27/95 dgp Same for enum cscGetNextResolution.
- 6/30/95 dgp GDSaveGamma(NULL) and GDRestoreGamma(NULL) now save and restore ALL devices.
- 7/3/95 dgp After the first request, GDSaveGamma() ignores subsequent requests to save the same
- device's gamma table. GDRestoreGamma() no longer discards the saved copy, so multiple
- calls to GDRestoreGamma() will all be effective. The effect of these changes is that
- if you have multiple nested pairs of calls to GDSaveGamma and GDRestoreGamma, you will
- end up with the desired result: every RestoreGamma will restore the screen to its
- original gamma, same as it had at the time of the first call to GDSaveGamma.
- 8/10/95 bt & dgp. Bosco Tjan, tjan@cs.umn.edu, found that the conditionals needed to be
- adjusted to be compatible with Symantec C 8, because their Video.h is different from Apple's.
- 9/26/95 dgp. For compatibility with the ETO18 (CW7) universal headers, eliminated the now obsolete
- typedefs of DepthMode (unsigned short) and DisplayModeID (unsigned long).
- 10/4/95 dgp Added code to GDCardName() to check for the presence of the Slot Manager, and
- just return an empty string "" if it's not present. This will prevent crashes on PCI Macs.
- 10/4/95 dgp Added GDSwitchMode() which implements cscSwitchMode as documented in Designing PCI
- Video Cards and Drivers.
- 10/24/95 dgp Added GDGetDelay and GDSetDelay to implement the custom video driver calls
- offered by the 7500/8500 video driver.
- 10/25/95 dgp After clarification from Fernando, fixed bug in GDGetDelays, so it should
- now work reliably. I didn't know that I had to set the validMask bits.
- 12/4/95 dgp As requested by David Brainard, added #def of cscSwitchMode for backward compatibility
- with older versions of THINK C.
- 3/4/96 dgp made compatible with THINK C 8, by replacing "SYMANTEC_C" by "SYMANTEC_C || THINK_C".
- 3/7/96 dgp Note that cscSetEntries reads from table[0],.... whereas cscGetEntries writes to table[start],....
- 5/1/96 dgp added GDDisposeGamma() to free the gamma tables.
- 5/28/96 dgp added test for UNIVERSAL_INTERFACES_VERSION<0x0212.
- */
-
- #include "VideoToolbox.h"
- #include <ROMDefs.h> // catDisplay,typeVideo,sRsrcName,sGammaDir
- //#include <Displays.h>
- void GetCPUProperties(char *cpuName,long *cpuHz,Boolean *hasL2Cache);
- void GetVideoProperties(GDHandle device,char *slotName,char *cardName,char *modelName);
- Boolean IsPCIMac(void);
-
-
- #if PRAGMA_ALIGN_SUPPORTED || __MWERKS__
- #pragma options align=mac68k
- #endif
-
- #if !UNIVERSAL_HEADERS
- /* these declarations appear in Video.h, universal version 1 and later */
- struct VDSwitchInfoRec{
- unsigned short csMode;
- unsigned long csData;
- unsigned short csPage;
- Ptr csBaseAddr;
- unsigned long csReserved;
- };
- typedef struct VDSwitchInfoRec VDSwitchInfoRec;
- enum{cscGetCurMode=10};
- #endif
- #if UNIVERSAL_HEADERS<2
- enum{dRAMBasedMask=0x0040}; /* dCtlDriver is a handle (1) or pointer (0) */
- typedef unsigned long UInt32;
- #endif
- #if UNIVERSAL_HEADERS<2 || SYMANTEC_C || THINK_C || __MWERKS__>=0x700
- /* These declarations appeared in Apple's Video.h, universal version 2.0a3, */
- /* and in "Universal Interfaces DDK v23c5. Monday, May 15, 1995"
- /* but not in previous or subsequent versions (e.g. 2.1 aka ETO18),
- /* until version 2.1.2 ETO 20, May 1996. */
- // The version macro UNIVERSAL_INTERFACES_VERSION is defined in Apple's ConditionalMacros.h,
- // but only since version 2.1 (which was distributed with CodeWarrior 8).
- #if UNIVERSAL_INTERFACES_VERSION<0x0212
- struct VDResolutionInfoRec {
- unsigned long csPreviousDisplayModeID; /* ID of the previous resolution in a chain */
- unsigned long csDisplayModeID; /* ID of the next resolution */
- unsigned long csHorizontalPixels; /* # of pixels in a horizontal line */
- unsigned long csVerticalLines; /* # of lines in a screen */
- Fixed csRefreshRate; /* Vertical Refresh Rate in Hz */
- unsigned short csMaxDepthMode; /* 0x80-based number representing max bit depth */
- unsigned long csResolutionFlags; /* flag bits */
- unsigned long csReserved; /* Reserved */
- };
- typedef struct VDResolutionInfoRec VDResolutionInfoRec;
- typedef VDResolutionInfoRec *VDResolutionInfoPtr;
- #define cscGetNextResolution 17 /* this won't break even if cscSwitchMode has already been declared as an enum */
- #define cscSwitchMode 10 /* this won't break even if cscSwitchMode has already been declared as an enum */
- #endif
- #endif
-
- typedef struct VDFlagRec {
- unsigned char flag;
- char pad;
- } VDFlagRec;
-
- typedef struct VDDefModeRec{
- unsigned char spID;
- char pad;
- } VDDefModeRec;
-
- typedef struct {
- short flags;
- short blanks[3];
- short open;
- short prime;
- short control;
- short status;
- short close;
- Str255 name;
- } VideoDriver;
- VideoDriver *GDDriverAddress(GDHandle device);
-
- typedef struct {
- short csCode; // control code
- short length; // total parameter block bytes
- char param[]; // control call data
- } ScrnCtl;
-
- typedef struct {
- short spDrvrHw; // Slot Manager ID
- short slot; // Number of slot
- long dCtlDevBase; // Start of device's address space
- short mode; // screen characteristics
- short flagMask; // Which flag bits are used
- short flags; // device state: bit 0 = 0 = mono; bit 0 = 1 = color;
- // bit 11 = 1 = startup device; bit 15 = 1 = active
- short colorTable; // 'clut' id, default = -1
- short gammaTable; // Selects color intensity, default (MacII) = -1
- Rect globalRect; // global rectangle, main device topLeft = 0,0
- short ctlCount; // total control calls
- ScrnCtl ctl;
- } Scrn;
-
- typedef struct {
- short scrnCount; // Total devices
- Scrn scrn;
- } Scrns; // 'scrn' resource
-
- #if PRAGMA_ALIGN_SUPPORTED || __MWERKS__
- #pragma options align=reset
- #endif
-
- Scrn **GDGetScrn(GDHandle device);
-
- OSErr GDGetNextResolution(GDHandle device,unsigned long previousDisplayModeID
- ,unsigned long *displayModeIDPtr,unsigned long *horizontalPixelsPtr
- ,unsigned long *verticalLinesPtr,Fixed *refreshRatePtr
- ,unsigned short *maxDepthModePtr);
-
- OSErr GDGetDisplayMode(GDHandle device,unsigned long *displayModeIDPtr
- ,unsigned short *modePtr,unsigned short *pagePtr,Ptr *baseAddrPtr)
- /*
- It tells you the current display mode, etc., but only if the video driver
- supports the Display Manager.
- */
- {
- VDSwitchInfoRec vdSwitchInfo;
- int error;
-
- if(device==NULL || (*device)->gdRefNum==0) return statusErr;
- error=GDStatus((*device)->gdRefNum,cscGetCurMode,(Ptr) &vdSwitchInfo);
- if(displayModeIDPtr!=NULL) *displayModeIDPtr=vdSwitchInfo.csData;
- if(modePtr!=NULL) *modePtr=vdSwitchInfo.csMode;
- if(pagePtr!=NULL) *pagePtr=vdSwitchInfo.csPage;
- if(baseAddrPtr!=NULL) *baseAddrPtr=vdSwitchInfo.csBaseAddr;
- return error;
- }
-
- OSErr GDGetNextResolution(GDHandle device,unsigned long previousDisplayModeID
- ,unsigned long *displayModeIDPtr,unsigned long *horizontalPixelsPtr
- ,unsigned long *verticalLinesPtr,Fixed *refreshRatePtr
- ,unsigned short *maxDepthModePtr)
- /*
- Tells you the next available displayModeID, after previousDisplayModeID.
- This is a new call, introduced for PCI video drivers.
- */
- {
- VDResolutionInfoRec vdSwitchInfo;
- int error;
-
- if(device==NULL || (*device)->gdRefNum==0) return statusErr;
- vdSwitchInfo.csPreviousDisplayModeID=previousDisplayModeID;
- error=GDStatus((*device)->gdRefNum,cscGetNextResolution,(Ptr) &vdSwitchInfo);
- if(displayModeIDPtr!=NULL) *displayModeIDPtr=vdSwitchInfo.csDisplayModeID;
- if(horizontalPixelsPtr!=NULL) *horizontalPixelsPtr=vdSwitchInfo.csHorizontalPixels;
- if(verticalLinesPtr!=NULL) *verticalLinesPtr=vdSwitchInfo.csVerticalLines;
- if(refreshRatePtr!=NULL) *refreshRatePtr=vdSwitchInfo.csRefreshRate;
- if(maxDepthModePtr!=NULL) *maxDepthModePtr=vdSwitchInfo.csMaxDepthMode;
- return error;
- }
-
- OSErr GDSetPageDrawn(GDHandle device,short page)
- // Select a page of video memory to draw into.
- {
- int error;
- short flags;
- Ptr baseAddr;
- static long qD=-1;
-
- if(qD==-1)Gestalt(gestaltQuickdrawVersion,&qD);
- error=GDGetPageBase(device,page,&baseAddr);
- if(!error){
- if(qD>=gestalt32BitQD){
- flags=GetPixelsState((**device).gdPMap);
- LockPixels((**device).gdPMap);
- }
- (**(**device).gdPMap).baseAddr=baseAddr;
- if(qD>=gestalt32BitQD){
- GDeviceChanged(device);
- SetPixelsState((**device).gdPMap,flags);
- }
- }
- return error;
- }
-
- OSErr GDSetPageShown(GDHandle device,short page)
- // Select a page of video memory for display.
- {
- int error;
- short mode;
-
- error=GDGetMode(device,&mode,NULL,NULL);
- if(error)return error;
- return GDSetMode(device,mode,page,NULL);
- }
-
- short GDType(GDHandle device)
- // Returns what would normally be in (**device).gdType, for occasions when
- // the GDevice record might be invalid because you called GDSetMode().
- {
- int error;
- static ColorSpec white={255,0xffff,0xffff,0xffff},black={0,0,0,0};
-
- error=GDSetEntries(device,0,0,&white);
- if(!error)return clutType;
- error=GDDirectSetEntries(device,0,0,&black);
- if(!error)return directType;
- return fixedType;
- }
-
- short GDPixelSize(GDHandle device)
- // Returns what would normally be in (**(**device).gdPMap).pixelSize, for occasions
- // when the GDevice record might be invalid because you called GDSetMode().
- // Exception: if this is merely a device record, with no associated device driver,
- // then we just return (**(**device).gdPMap).pixelSize
- {
- int error;
- short mode;
-
- if((**device).gdRefNum==0)return (**(**device).gdPMap).pixelSize;
- error=GDGetMode(device,&mode,NULL,NULL);
- return GDModePixelSize(device,mode);
- }
-
- short GDModePixelSize(GDHandle device,short mode)
- // Returns the pixelSize associated with a given video mode.
- // If you've changed the mode by calling GDSetMode and you're running a System
- // older than 6.0.5 the answer may may be wrong for some of the newer video cards,
- // because they have ideosynchratic associations of video mode and pixel size.
- {
- short j;
- long version;
-
- if(mode==(**device).gdMode)return (**(**device).gdPMap).pixelSize;
- Gestalt(gestaltSystemVersion,&version);
- if(version>=0x605){ // Need new Palette Manager for reliable answer.
- for(j=5;j>=0;j--)if(mode==HasDepth(device,1<<j,0,0))return 1<<j;
- } else return 1<<(mode&7); // Unreliable.
- return 0;
- }
-
- Boolean GDHasMode(GDHandle device,short mode,short *pixelSizePtr,short *pagesPtr);
-
- Boolean GDHasMode(GDHandle device,short mode,short *pixelSizePtr,short *pagesPtr)
- // Returns 0 if no such mode, returns 1 if mode is available.
- // If pixelSizePtr is not NULL, then sets *pixelSizePtr to pixelSize or -1 if unknown.
- // If pagesPtr is not NULL, then sets *pagesPtr to pages.
- {
- short pixelSize,i,hasDepthWorks,pages;
- int error;
- long system;
-
- Gestalt(gestaltSystemVersion,&system);
- // On Mac IIci, Sys 6.07, HasDepth returns "mode" of 0x100 at all legal depths.
- hasDepthWorks= system>=0x605 // New Palette Manager.
- && HasDepth(device,(**(**device).gdPMap).pixelSize,0,0)==(**device).gdMode;
- if(hasDepthWorks){
- for(i=0;i<6;i++){
- pixelSize=1<<i;
- if(mode!=HasDepth(device,pixelSize,0,0))continue;
- if(pixelSizePtr!=NULL)*pixelSizePtr=pixelSize;
- if(pagesPtr!=NULL){
- error=GDGetPageCnt(device,mode,&pages);
- if(error)pages=1;
- *pagesPtr=pages;
- }
- return 1;
- }
- return 0;
- }else{
- // If HasDepth doesn't work properly then we can still find out whether the
- // mode is available by asking the video driver for a page count, but
- // I don't know of any discreet way to find out the pixelSize.
- // Calling SetDepth would work, but that would irritate the user who has to
- // watch and wait.
- error=GDGetPageCnt(device,mode,&pages);
- if(error)pages=0;
- if(pagesPtr!=NULL)*pagesPtr=pages;
- if(mode==(**device).gdMode)pixelSize=(**(**device).gdPMap).pixelSize;
- else pixelSize=-1; // Unknown.
- if(pixelSizePtr!=NULL)*pixelSizePtr=pixelSize;
- return (pages>0);
- }
- }
-
- short gdClutSizeTable[33]={0,1<<1,1<<2,0,1<<4,0,0,0,1<<8,0,0,0,0,0,0,0,1<<5
- ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1<<8};
-
- long GDColors(GDHandle device)
- // Returns the number of colors, in the current mode.
- {
- long colors=0;
- short pixelSize;
-
- if(device==NULL)return 2; // for compatibility with 1-bit QuickDraw
- pixelSize=(**(**device).gdPMap).pixelSize;
- if(pixelSize>=1 && pixelSize<=8)colors=1<<pixelSize;
- if(pixelSize==16)colors=1L<<15;
- if(pixelSize==32)colors=1L<<24;
- return colors;
- }
-
- short GDClutSize(GDHandle device)
- // Returns the number of entries in the clut, in the current mode.
- {
- short clutSize;
-
- // Method 1. Estimate clut size from pixel size.
- clutSize=gdClutSizeTable[(**(**device).gdPMap).pixelSize];
-
- #if 0
- // Method 2. Measure the clut's size by trying to load it.
- if(GDType(device)==directType){
- int error,i;
- static const ColorSpec white={255,0xffff,0xffff,0xffff},black={0,0,0,0};
- ColorSpec *table;
- for(clutSize=256;clutSize>1;clutSize>>=1){
- table=GDNewLinearColorTable(device);
- if(table==NULL)PrintfExit("GDClutSize: out of memory.\n");
- error=GDDirectSetEntries(device,0,clutSize-1,table);
- DisposePtr((Ptr)table);
- if(!error)break;
- }
- }
- #endif
-
- return clutSize;
- }
-
- short GDDacSize(GDHandle device)
- // Figures out how many bits in the video dac. Answers for each device are cached.
- {
- short dacSize,i;
- static short dacSizeCache[MAX_SCREENS];
- static GDHandle deviceCache[MAX_SCREENS];
- int error;
- GammaTbl *gammaTblPtr=NULL;
-
- for(i=0;i<MAX_SCREENS;i++)if(device==deviceCache[i])return dacSizeCache[i];
- error=GDGetGamma(device,&gammaTblPtr); // Takes 200 µs.
- if(error || gammaTblPtr==NULL || gammaTblPtr->gDataWidth==0)dacSize=8; // Oops. Take a guess.
- else dacSize=gammaTblPtr->gDataWidth;
- for(i=0;i<MAX_SCREENS;i++)if(NULL==deviceCache[i]){
- deviceCache[i]=device;
- dacSizeCache[i]=dacSize;
- break;
- }
- return dacSize;
- }
-
- ColorSpec *GDNewLinearColorTable(GDHandle device)
- // Creates a default table for use when gdType==directType.
- {
- short clutSize,i;
- ColorSpec *table,*linearTable;
-
- clutSize=GDClutSize(device);
- table=linearTable=(ColorSpec *)NewPtr(clutSize*sizeof(linearTable[0]));
- if(linearTable!=NULL)for(i=0;i<clutSize;i++){
- table->rgb.red=table->rgb.green=table->rgb.blue
- =(0xffffL*i+clutSize/2)/(clutSize-1);
- table++;
- }
- return linearTable;
- }
-
- /*
- Nominally equivalent to Apple's RestoreDeviceClut(), which is only available
- since System 6.05. However, I find that Apple's routine sometimes does nothing,
- whereas this routine always works. Passing a NULL argument causes restoration of
- cluts of all video devices.
- */
- OSErr GDRestoreDeviceClut(GDHandle device)
- {
- int error,lastError;
-
- // If NULL, then call ourselves for each device.
- if(device==NULL){
- lastError=0;
- device=GetDeviceList();
- while(device!=NULL) {
- if(TestDeviceAttribute(device,screenDevice) && TestDeviceAttribute(device,screenActive)){
- error=GDRestoreDeviceClut(device);
- if(error)lastError=error;
- }
- device=GetNextDevice(device);
- }
- return lastError;
- }
- if(GDType(device)!=directType){
- error=GDSetEntries(device,0,(**(**(**device).gdPMap).pmTable).ctSize
- ,((**(**(**device).gdPMap).pmTable)).ctTable);
- }else error=GDSetGamma(device,NULL);
- return error;
- }
-
- GammaTbl **savedGammaTable[MAX_SCREENS];
-
- OSErr GDDisposeGamma(GDHandle device)
- {
- int error=0,lastError,i;
-
- // If NULL, then call ourselves for each device.
- if(device==NULL){
- lastError=0;
- device=GetDeviceList();
- while(device!=NULL) {
- if(TestDeviceAttribute(device,screenDevice) && TestDeviceAttribute(device,screenActive)){
- error=GDDisposeGamma(device);
- if(error)lastError=error;
- }
- device=GetNextDevice(device);
- }
- return lastError;
- }
- if(device==NULL || (*device)->gdType==fixedType)return 0;
- i=GetScreenIndex(device);
- if(i>=MAX_SCREENS)return 1;
- if(savedGammaTable[i]==NULL)return 0;
- DisposeHandle((Handle)savedGammaTable[i]);
- savedGammaTable[i]=NULL;
- return error;
- }
-
- OSErr GDSaveGamma(GDHandle device)
- {
- GammaTbl *gamma;
- int error,lastError;
- long size;
- int i;
-
- // If NULL, then call ourselves for each device.
- if(device==NULL){
- lastError=0;
- device=GetDeviceList();
- while(device!=NULL) {
- if(TestDeviceAttribute(device,screenDevice) && TestDeviceAttribute(device,screenActive)){
- error=GDSaveGamma(device);
- if(error)lastError=error;
- }
- device=GetNextDevice(device);
- }
- return lastError;
- }
- if(device==NULL || (*device)->gdType==fixedType)return 0;
- i=GetScreenIndex(device);
- if(i>=MAX_SCREENS)return 1;
- if(savedGammaTable[i]!=NULL)return 0;
- error=GDGetGamma(device,&gamma);
- if(error)return error;
- size=gamma->gChanCnt*gamma->gDataCnt;
- if(gamma->gDataWidth>8)size*=2;
- size+=sizeof(GammaTbl)+gamma->gFormulaSize;
- error=PtrToHand(gamma,(Handle *)&savedGammaTable[i],size);
- return error;
- }
-
- OSErr GDRestoreGamma(GDHandle device)
- {
- int i,error,lastError;
-
- // If NULL, then call ourselves for each device.
- if(device==NULL){
- lastError=0;
- device=GetDeviceList();
- while(device!=NULL) {
- if(TestDeviceAttribute(device,screenDevice) && TestDeviceAttribute(device,screenActive)){
- error=GDRestoreGamma(device);
- if(error)lastError=error;
- }
- device=GetNextDevice(device);
- }
- return lastError;
- }
- if((*device)->gdType==fixedType)return 0;
- i=GetScreenIndex(device);
- if(i>=MAX_SCREENS || savedGammaTable[i]==NULL)return 1;
- error=GDSetGamma(device,*savedGammaTable[i]);
- if(error)return error;
- if(0){
- DisposeHandle((Handle)savedGammaTable[i]);
- savedGammaTable[i]=NULL;
- }
- return 0;
- }
-
- OSErr GDGetDefaultGamma(GDHandle device,GammaTbl **gammaTbl)
- // Looks for a default gamma table in both places that Apple says to look,
- // but usually comes up empty handed.
- {
- int error,i,slot;
- Scrn **scrn;
- GammaTbl **gammaHandle,*gamma;
- SpBlock spBlock;
- Ptr ptr;
-
- gammaHandle=NULL;
- if(CountResources('gama')>0){// Any 'gama' resources available in System file?
- // Check to see if 'scrn' resource in System file specifies a 'gama' resource.
- scrn=GDGetScrn(device);
- if(scrn!=NULL && (**scrn).gammaTable!=-1)
- gammaHandle=(GammaTbl **)GetResource('gama',(**scrn).gammaTable);
- DisposeHandle((Handle)scrn);
- }
- if(gammaHandle!=NULL){
- // Got gamma table from 'gama' resource.
- gamma=(GammaTbl *)NewPtr(GetHandleSize((Handle)gammaHandle));
- if(gamma==NULL)return MemError();
- BlockMove(*gammaHandle,gamma,GetHandleSize((Handle)gammaHandle));
- DisposeHandle((Handle)gammaHandle);
- }else{
- // Try to get this device's default gamma table from Slot Manager.
- spBlock.spSlot=slot=GetDeviceSlot(device);
- spBlock.spID=0;
- spBlock.spExtDev=0;
- spBlock.spTBMask=3; // match only spCategory and spCType
- spBlock.spCategory=catDisplay;
- spBlock.spCType=typeVideo; // this might be too restrictive, excludes LCD
- do{
- error=SNextTypeSRsrc(&spBlock);
- if(error)return error;
- }while(spBlock.spSlot!=slot || spBlock.spRefNum!=(**device).gdRefNum);
-
- if(0){
- // Print sResource name
- spBlock.spID=sRsrcName;
- error=SGetCString(&spBlock);
- printf("Slot resource \"%s\"\n",spBlock.spResult);
- if(error)return error;
- DisposePtr((Ptr)spBlock.spResult);
- }
-
- // Look for gamma directory. Unfortunately many video devices don't have one.
- spBlock.spID=sGammaDir;
- error=SFindStruct(&spBlock);
- if(error)return error;
-
- // Retrieve default gamma table
- spBlock.spID=0x80;
- error=SGetBlock(&spBlock);
- if(error)return error;
- gamma=(GammaTbl *)spBlock.spResult;
- ptr=(Ptr)spBlock.spResult+6;
- if(0)printf("Gamma table \"%s\", %ld bytes\n",ptr,GetPtrSize((Ptr)gamma));
- ptr+=strlen(ptr)+1; // table is just past string
- ptr=(Ptr)((long)(ptr+1)&~1L); // round up to even address
- i=ptr-(Ptr)gamma;
- BlockMove(ptr,(Ptr)gamma,GetPtrSize((Ptr)gamma)-i);
- SetPtrSize((Ptr)gamma,GetPtrSize((Ptr)gamma)-i);
- }
- *gammaTbl=gamma;
- return 0;
- }
-
- Scrn **GDGetScrn(GDHandle device)
- // Returns handle to a copy of the specific scrn resource for this device,
- // or NULL if none.
- {
- int error=0,i,j;
- Scrns **scrns;
- Scrn *scrn,**scrnHandle;
- ScrnCtl *ctl;
- int scrnCount;
- long size;
-
- scrns=(Scrns **)GetResource('scrn',0);
- if(ResError())return NULL;
- HLockHi((Handle)scrns);
- scrnCount=(**scrns).scrnCount;
- scrn=&(**scrns).scrn;
- for(i=0;i<scrnCount;i++){
- if(0 && scrn->slot==GetDeviceSlot(device)){
- printf("Slot %d,",(int)scrn->slot);
- printf("mode %d,",(int)scrn->mode);
- printf("colorTable %d,",(int)scrn->colorTable);
- printf("gammaTable %d,",(int)scrn->gammaTable);
- printf("%d control calls:",(int)scrn->ctlCount);
- }
- ctl=&scrn->ctl;
- for(j=0;j<scrn->ctlCount;j++){
- if(0 && scrn->slot==GetDeviceSlot(device))printf(" %d",(int)ctl->csCode);
- ctl=(ScrnCtl *)((long)(ctl+1)+ctl->length);
- }
- if(0 && scrn->slot==GetDeviceSlot(device))printf("\n");
- size=(long)ctl-(long)scrn;
- if(scrn->slot==GetDeviceSlot(device))break;
- scrn=(Scrn *)ctl;
- }
- if(i<scrnCount){
- if(error)return NULL;
- scrnHandle=(Scrn **)NewHandle(size);
- BlockMove(scrn,*scrnHandle,size);
- }else scrnHandle=NULL;
- ReleaseResource((Handle)scrns);
- return scrnHandle;
- }
-
- OSErr GDUncorrectedGamma(GDHandle device)
- /*
- Loads a linear gamma table into the specified video device, to defeat the
- driver's attempt to do gamma correction.
-
- According to Designing Cards and Drivers, 3rd edition, passing a NULL
- GammaTblPtr instructs the driver to create a linear table.
-
- */
- {
- int error,i;
- GammaTbl *gamma=NULL;
- char *gData;
-
- if(0){
- /*
- The the following code first examines the current
- gamma table, and, if it's a plain vanilla table, as described in Designing Cards
- and Drivers, then we write-in the desired linear table. If it's fancy (or if the
- driver doesn't support GDGetGamma) then we pass a NULL pointer, letting the driver
- create the new table. Hopefully this will work with all drivers.
- */
- error=GDGetGamma(device,&gamma);
- if(!error && gamma->gVersion==0 && gamma->gChanCnt==1 && gamma->gDataWidth<=8){
- // Overwrite the standard table
- gData = (char *)&gamma->gFormulaData+gamma->gFormulaSize;
- for(i=0;i<gamma->gDataCnt;i++)gData[i]=i;
- }else{
- // A fancy table implies a new driver, so let it do the work.
- gamma=NULL;
- }
- }
- error=GDSetGamma(device,gamma);
- return error;
- }
-
- /* KillIO doesn't do anything, so I didn't bother to implement it. */
-
- OSErr GDPrintGammaTable(FILE *o,GDHandle device)
- {
- unsigned char *byte;
- unsigned short *word;
- int error,i,j,identity;
- GammaTbl *gamma;
-
- if((**device).gdType==fixedType)return statusErr;
- error=GDGetGamma(device,&gamma);
- if(error){
- fprintf(o,"GetGamma: GDGetGamma() error %d\n",error);
- if(error==statusErr)
- fprintf(o,"The video driver doesn't support this call.\n");
- return error;
- }
- byte=(unsigned char *)gamma->gFormulaData+gamma->gFormulaSize;
- word=(unsigned short *)byte;
- identity=1;
- if(gamma->gDataWidth<=8)
- for(i=0;i<gamma->gDataCnt;i++)identity &= (i==byte[i]);
- else
- for(i=0;i<gamma->gDataCnt;i++)identity &= (i==word[i]);
- if(identity){
- fprintf(o,"Gamma Table: identity transformation\n");
- }else{
- fprintf(o,"Gamma Table:\n");
- fprintf(o,"at 0x%lx,gDataWidth %d,gDataCnt %d,gVersion %d,gType %d,gFormulaSize %d,gChanCnt %d\n"
- ,gamma,(int)gamma->gDataWidth,(int)gamma->gDataCnt,(int)gamma->gVersion
- ,(int)gamma->gType,(int)gamma->gFormulaSize,(int)gamma->gChanCnt);
- for(i=0;i<gamma->gDataCnt;i+=64) {
- fprintf(o,"%3d: ",i);
- if(gamma->gDataWidth<=8)
- for(j=0;j<16;j++) fprintf(o," %3u",byte[i+j]);
- else
- for(j=0;j<16;j++) fprintf(o," %3u",word[i+j]);
- fprintf(o,"\n");
- }
- }
- return 0;
- }
-
- OSErr GDReset(GDHandle device, short *modePtr, short *pagePtr, Ptr *baseAddrPtr)
- /*
- Initialize the video card to its startup state, usually 1 bit per pixel. Returns
- the parameters of that state.
- */
- {
- VDPageInfo myVDPageInfo;
- int error;
-
- if(device==NULL || (*device)->gdRefNum==0) return controlErr;
- myVDPageInfo.csMode= *modePtr;
- myVDPageInfo.csPage= *pagePtr;
- error=GDControl((*device)->gdRefNum,cscReset,(Ptr) &myVDPageInfo);
- *modePtr=myVDPageInfo.csMode;
- *pagePtr=myVDPageInfo.csPage;
- if(baseAddrPtr!=NULL) *baseAddrPtr=myVDPageInfo.csBaseAddr;
- return error;
- }
-
- OSErr GDSetMode(GDHandle device,short mode,short page,Ptr *baseAddrPtr)
- {
- VDPageInfo myVDPageInfo;
- int error;
-
- if(device==NULL || (*device)->gdRefNum==0) return controlErr;
- myVDPageInfo.csMode=mode;
- myVDPageInfo.csPage=page;
- error=GDControl((*device)->gdRefNum,cscSetMode,(Ptr) &myVDPageInfo);
- if(baseAddrPtr!=NULL) *baseAddrPtr=myVDPageInfo.csBaseAddr;
- return error;
- }
-
- OSErr GDSwitchMode(GDHandle device,short mode,long displayModeID,short page,Ptr *baseAddrPtr);
-
- OSErr GDSwitchMode(GDHandle device,short mode,long displayModeID,short page,Ptr *baseAddrPtr)
- /* cscSwitchMode is documented in Designing PCI Video Cards and Drivers. */
- {
- VDSwitchInfoRec vdSwitchInfo;
- int error;
-
- if(device==NULL || (*device)->gdRefNum==0) return controlErr;
- vdSwitchInfo.csMode=mode;
- vdSwitchInfo.csData=displayModeID;
- vdSwitchInfo.csPage=page;
- error=GDControl((*device)->gdRefNum,cscSwitchMode,(Ptr) &vdSwitchInfo);
- if(baseAddrPtr!=NULL) *baseAddrPtr=vdSwitchInfo.csBaseAddr;
- return error;
- }
-
- OSErr GDSetEntriesByType(GDHandle device,short start,short count,ColorSpec *table)
- // Calls GDSetEntries or GDDirectSetEntries or nothing, as appropriate.
- // Assumes that the GDevice record is valid, i.e. that the user has not
- // called GDSetMode.
- {
- switch((*device)->gdType){
- case fixedType:
- return statusErr;
- case clutType:
- return GDSetEntries(device,start,count,table);
- case directType:
- return GDDirectSetEntries(device,start,count,table);
- }
- return 1;
- }
-
- OSErr GDSetEntriesByTypeHighPriority(GDHandle device,short start,short count
- ,ColorSpec *table)
- {
- char priority;
- int error;
-
- priority=7;
- SwapPriority(&priority);
- error=GDSetEntriesByType(device,start,count,table);
- SwapPriority(&priority);
- return error;
- }
-
- OSErr GDSetEntries(GDHandle device,short start,short count,ColorSpec *table)
- // Note that cscSetEntries reads from table[0],.... whereas cscGetEntries writes to table[start],....
- {
- VDSetEntryRecord vDSetEntryRecord;
- int error;
-
- if(device==NULL || (*device)->gdRefNum==0) return controlErr;
- vDSetEntryRecord.csStart=start;
- vDSetEntryRecord.csCount=count;
- vDSetEntryRecord.csTable=table;
- error=GDControl((*device)->gdRefNum,cscSetEntries,(Ptr) &vDSetEntryRecord);
- return error;
- }
-
- OSErr GDSetGamma(GDHandle device, GammaTbl *gamma)
- {
- int error;
- VDGammaRecord myVDGammaRecord;
-
- myVDGammaRecord.csGTable=(Ptr)gamma;
- error=GDControl((*device)->gdRefNum,cscSetGamma,(Ptr) &myVDGammaRecord);
- return error;
- }
-
- OSErr GDGrayPage(GDHandle device,short page)
- /*
- Called "GrayScreen" in Designing Cards and Drivers, 3rd Ed. Fills the specified
- page with gray, i.e. the dithered desktop pattern. I'm not aware of any
- particular advantage in using this instead of FillRect().
-
- Designing Cards and Drivers, 3rd Edition, Chapter 9, says that for direct
- devices, i.e. >8 bit pixels, the driver will also load a linear,
- gamma-corrected, gray color table.
-
- Contrary to the documentation, version 2 (in System 6.03) of the video driver
- for Apple's old video card requires that one supply the current mode as well.
- Supplying a garbage mode screwed up the screen and soon hung the software. So
- this code first obtains the current mode, and then supplies it in the GrayPage
- Control call.
- */
- {
- VDPageInfo myVDPageInfo;
- int error;
- /* The rest of the arguments are used soley for the bug fix */
- short mode=0; /* should be ignored, but isn't */
- short actualPage; /* ignored */
- Ptr baseAddr; /* ignored */
-
- if(device==NULL || (*device)->gdRefNum==0) return controlErr;
-
- /* Work around driver bug: get the mode */
- error=GDGetMode(device,&mode,&actualPage,&baseAddr);
- if(error)return error;
- myVDPageInfo.csMode=mode;
-
- myVDPageInfo.csPage=page;
- error=GDControl((*device)->gdRefNum,cscGrayPage,(Ptr) &myVDPageInfo);
- return error;
- }
-
- OSErr GDSetGray(GDHandle device,Boolean flag)
- /*
- Tells the driver whether you want colors (flag==0), or prefer that all colors be
- mapped to luminance-equivalent gray tones? (flag==1).
- */
- {
- VDFlagRec myVDFlagRec;
- int error;
-
- if(device==NULL || (*device)->gdRefNum==0) return controlErr;
- myVDFlagRec.flag=flag;
- error=GDControl((*device)->gdRefNum,cscSetGray,(Ptr) &myVDFlagRec);
- return error;
- }
-
- OSErr GDSetInterrupt(GDHandle device,Boolean flag)
- /*
- Set flag to 1 to enable VBL interrupts of this card, or 0 to disable.
- I don't know when it's appropriate to call this.
- */
- {
- VDFlagRec myVDFlagRec;
- int error;
-
- if(device==NULL || (*device)->gdRefNum==0) return controlErr;
- myVDFlagRec.flag=flag;
- error=GDControl((*device)->gdRefNum,cscSetInterrupt,(Ptr) &myVDFlagRec);
- return error;
- }
-
- OSErr GDDirectSetEntries(GDHandle device,short start,short count,ColorSpec *table)
- /*
- If your pixel depth is >8 then the cscSetEntries Control call is disabled, and you use
- cscDirectSetEntries instead. Except for that, GDDirectSetEntries is identical to GDSetEntries.
- */
- {
- VDSetEntryRecord vDSetEntryRecord;
- int error;
-
- if(device==NULL || (*device)->gdRefNum==0) return controlErr;
- vDSetEntryRecord.csStart=start;
- vDSetEntryRecord.csCount=count;
- vDSetEntryRecord.csTable=table;
- error=GDControl((*device)->gdRefNum,cscDirectSetEntries,(Ptr) &vDSetEntryRecord);
- return error;
- }
-
- OSErr GDSetDefaultMode(GDHandle device,short mode)
- /*
- Supposedly, you tell it what mode you want to start up with when you reboot.
- (I've never been able to get this to work. No error and no effect. Perhaps I've
- misunderstood its purpose.)
- */
- {
- VDDefModeRec myVDDefModeRec;
- int error;
-
- if(device==NULL || (*device)->gdRefNum==0) return controlErr;
- myVDDefModeRec.spID=mode;
- error=GDControl((*device)->gdRefNum,cscSetDefaultMode,(Ptr) &myVDDefModeRec);
- return error;
- }
-
- OSErr GDGetMode(GDHandle device,short *modePtr,short *pagePtr,Ptr *baseAddrPtr)
- /*
- It tells you the current mode, page of video memory, and the base address of that
- page.
- */
- {
- VDPageInfo myVDPageInfo;
- int error;
-
- if(device==NULL || (*device)->gdRefNum==0) return statusErr;
- error=GDStatus((*device)->gdRefNum,cscGetMode,(Ptr) &myVDPageInfo);
- if(modePtr!=NULL)*modePtr=myVDPageInfo.csMode;
- if(pagePtr!=NULL)*pagePtr=myVDPageInfo.csPage;
- if(baseAddrPtr!=NULL) *baseAddrPtr=myVDPageInfo.csBaseAddr;
- return error;
- }
-
- OSErr GDGetEntries(GDHandle device,short start,short count,ColorSpec *table)
- // Note that cscSetEntries reads from table[0],.... whereas cscGetEntries writes to table[start],....
- /*
- This is much as you'd expect after reading GDSetEntries above. Note that unless
- the gamma table is linear, the values returned may not be the same as those
- originally passed by GDSetEntries. So call GDUncorrectedGamma first. Note that
- version 2 (in System 6.03) of the video driver for Apple's old video card had a
- bug and did not support "indexed" mode, i.e. start==-1. This is fixed in System
- 6.05. Apple's .Display_Video_Apple_RBV1 v. 0 video driver (built-in to Mac IIci)
- crashes if you attempt to make this call. However, that's a thing of the past,
- because we now first patch the driver to fix the bug. Try the demo TimeVideo.
- */
- {
- VDSetEntryRecord vDSetEntryRecord;
- int error;
- static Boolean bugsPatched=0;
- unsigned char *name;
- int version;
-
- if(device==NULL || (*device)->gdRefNum==0)return statusErr;
- if(!bugsPatched){
- PatchMacIIciVideoDriver();
- bugsPatched=1;
- }
-
- // Contrary to Apple's rules, these drivers crash if we attempt
- // a cscGetEntries call. So let's be polite and instead simply return
- // an error message indicating that this call is not available.
- name=GDName(device);
- version=GDVersion(device);
- if(EqualString(name,"\p.Display_Video_Apple_RBV1",1,1) && version==0)return statusErr;
- if(EqualString(name,"\p.Color_Video_Display",1,1) && version==9288)return statusErr;
- if(EqualString(name,"\p.Display_Video_Apple_DOMEMax",1,1) && version==2)return statusErr;
-
- vDSetEntryRecord.csStart=start;
- vDSetEntryRecord.csCount=count;
- vDSetEntryRecord.csTable=table;
- error=GDStatus((*device)->gdRefNum,cscGetEntries,(Ptr) &vDSetEntryRecord);
- return error;
- }
-
- OSErr GDGetPageCnt(GDHandle device,short mode,short *pagesPtr)
- /*
- Called "GetPages" in Designing Cards and Drivers, 3rd Ed. You tell it what mode
- you're interested in. It tells you how many pages of video ram are available.
- */
- {
- VDPageInfo myVDPageInfo;
- int error;
-
- if(device==NULL || (*device)->gdRefNum==0) return statusErr;
- myVDPageInfo.csMode=mode;
- error=GDStatus((*device)->gdRefNum,cscGetPageCnt,(Ptr) &myVDPageInfo);
- if(!error)*pagesPtr=myVDPageInfo.csPage;
- return error;
- }
-
- OSErr GDGetPageBase(GDHandle device,short page,Ptr *baseAddrPtr)
- /*
- Called "GetBaseAddr" in Designing Cards and Drivers, 3rd Ed. You tell it what
- page of video memory you're interested in (in the current video mode). It tells
- you the base address of that page.
- */
- {
- VDPageInfo myVDPageInfo;
- int error;
-
- if(device==NULL || (*device)->gdRefNum==0) return statusErr;
- myVDPageInfo.csPage=page;
- error=GDStatus((*device)->gdRefNum,cscGetPageBase,(Ptr) &myVDPageInfo);
- if(baseAddrPtr!=NULL) *baseAddrPtr=myVDPageInfo.csBaseAddr;
- return error;
- }
-
- OSErr GDGetGray(GDHandle device,Boolean *flagPtr)
- // It tells you what the flag is set to. Do you want colors? (flag==0) Or do you
- // want all colors mapped to luminance-equivalent gray tones? (flag==1).
- {
- VDFlagRec myVDFlagRec;
- int error;
-
- if(device==NULL || (*device)->gdRefNum==0) return statusErr;
- error=GDStatus((*device)->gdRefNum,cscGetGray,(Ptr) &myVDFlagRec);
- *flagPtr=myVDFlagRec.flag;
- return error;
- }
-
- OSErr GDGetInterrupt(GDHandle device,Boolean *flagPtr)
- // Get flag. 1 if VBL interrupts of this card are enabled. 0 if disabled.
- {
- VDFlagRec myVDFlagRec;
- int error;
-
- if(device==NULL || (*device)->gdRefNum==0) return statusErr;
- error=GDStatus((*device)->gdRefNum,cscGetInterrupt,(Ptr) &myVDFlagRec);
- *flagPtr=myVDFlagRec.flag;
- return error;
- }
-
- OSErr GDGetGamma(GDHandle device,GammaTbl **myGammaTblHandle)
- /*
- Returns a pointer to the Gamma table in the specified video device. (I.e. you
- pass it a pointer to your pointer, a handle, which it uses to load your
- pointer.)
-
- Note that version 2 (in System ≤6.03) of the video driver for Apple's old video
- card does not support this call due to a bug in the driver code. The later
- versions of the driver (3, 4, and 5, in System 6.04 and later) work correctly.
- */
- {
- int error;
- VDGammaRecord myVDGammaRecord;
-
- if(device==NULL || (*device)->gdRefNum==0) return statusErr;
- myVDGammaRecord.csGTable=NULL; // default address is NULL
- error=GDStatus((*device)->gdRefNum,cscGetGamma,(Ptr) &myVDGammaRecord);
- *myGammaTblHandle=(GammaTblPtr)myVDGammaRecord.csGTable;
- return error;
- }
-
- OSErr GDGetDefaultMode(GDHandle device,short *modePtr)
- // It tells you what the default mode is. I'm not sure what this means.
- {
- VDDefModeRec myVDDefModeRec;
- int error;
-
- if(device==NULL || (*device)->gdRefNum==0) return statusErr;
- error=GDStatus((*device)->gdRefNum,cscGetDefaultMode,(Ptr) &myVDDefModeRec);
- *modePtr=(unsigned char)myVDDefModeRec.spID;
- return error;
- }
-
- OSErr GDControl(int refNum,int csCode,Ptr csParamPtr)
- // Uses low-level PBControl() call to implement a "Control()" call that works!
- // I don't know why this wasn't discussed in Apple Tech Note 262.
- {
- CntrlParam control;
- int error;
-
- control.ioCompletion=NULL;
- control.ioCRefNum=refNum;
- control.csCode=csCode;
- *((Ptr *) &control.csParam[0]) = csParamPtr;
- error=PBControl((ParmBlkPtr) &control,0);
- return error;
- }
-
- OSErr GDStatus(int refNum,int csCode,Ptr csParamPtr)
- // Uses low-level PBStatus() call to implement a "Status()" call that works! The
- // need for this is explained in Apple Tech Note 262, which was issued in response
- // to my bug report in summer of '89.
- {
- CntrlParam control;
- int error;
-
- control.ioCompletion=NULL;
- control.ioCRefNum=refNum;
- control.csCode=csCode;
- *((Ptr *) &control.csParam[0]) = csParamPtr;
- error=PBStatus((ParmBlkPtr) &control,0);
- return error;
- }
-
- #if 0
- /*
- From: absurd@apple.apple.com (Tim Dierks, software saboteur)
- Date: Fri, 20 Nov 1992 00:38:14 GMT
- Organization: MacDTS Marauders
-
- Here's the right way to get the slot number of a monitor, given its
- GDevice: (as a bonus, this also gets the name of the card in
- question; to just get the slot, chop off all the lines after the
- *slot = ... line.
-
- 10/4/95 dgp added safety checks at beginning to make sure device handle is
- not NULL and that the Slot Manager is present (e.g. a PCI machine).
- */
-
- OSErr GetSlotAndName(GDHandle device,short *slot,char *name)
- { OSErr error;
- SpBlock spBlock;
- Boolean slotMgrPresent;
-
- slot=-1;
- name[0]=0;
- if(TrapAvailable(_SlotManager))slotMgrPresent=(SVersion(&spBlock)==noErr);
- else slotMgrPresent=0;
- if(!slotMgrPresent || device==NULL || (*device)->gdRefNum==0)return -1;
- *slot = (**(AuxDCEHandle)GetDCtlEntry((**device).gdRefNum)).dCtlSlot;
- spBlock.spSlot = *slot; // In the slot we're interested in
- spBlock.spID = 0;
- spBlock.spExtDev = 0;
- spBlock.spCategory = 1; // Get the board sResource
- spBlock.spCType = 0;
- spBlock.spDrvrSW = 0;
- spBlock.spDrvrHW = 0;
- spBlock.spTBMask = 0;
- error = SNextTypeSRsrc(&spBlock);
- if(error)return error;
- spBlock.spID = 2; // Getting the description string
- // spSPointer was set up by SNextTypesResource
- error = SGetCString(&spBlock);
- if(error)return error;
- strcpy(name,(char *)spBlock.spResult); // Get the returned string
- DisposePtr((Ptr)spBlock.spResult); // Undocumented; we have to dispose of it
- c2pstr(name);
- return noErr;
- }
- #endif
-
- char *GDCardName(GDHandle device)
- /*
- Returns the address of a C string containing the name of the video card. You
- should call DisposPtr() on the returned address when you no longer need it.
- Takes about 1.5 ms; I don't know why Apple's slot routines are so slow. This
- routine sets up the flags in the SNextTypeSRsrc() call quite differently from
- the above example, but I don't know if that matters, since I've been using this
- routine for a year or so without any problems.
-
- Now works for PCI video devices as well.
- */
- {
- AuxDCE **auxDCEHandle;
- SpBlock spBlock,spBlock1;
- Boolean slotMgrPresent;
- char slotName[32],cardName[32],modelName[32];
-
- GetVideoProperties(device,slotName,cardName,modelName); /* in Identify.c */
- if(strlen(cardName)>0){
- Ptr p;
- if(strlen(slotName)==0)strcpy(cardName,"Built-in video");
- p=NewPtr(strlen(cardName)+1);
- strcpy(p,cardName);
- return p;
- }
- if(TrapAvailable(_SlotManager))slotMgrPresent=(SVersion(&spBlock)==noErr);
- else slotMgrPresent=0;
- if(!slotMgrPresent || device==NULL || (*device)->gdRefNum==0){
- Ptr p;
- p=NewPtr(1);
- p[0]=0;
- return p;
- }
- auxDCEHandle = (AuxDCE **) GetDCtlEntry((*device)->gdRefNum);
- spBlock.spSlot = (**auxDCEHandle).dCtlSlot;
- spBlock.spCategory = 0;
- spBlock.spCType = 0;
- spBlock.spDrvrSW = 0;
- spBlock.spDrvrHW = 1;
- spBlock.spTBMask = 0xf;
- spBlock.spID = 0;
- spBlock.spExtDev = 0;
- if(SNextTypeSRsrc(&spBlock) == noErr) {
- spBlock1.spsPointer = spBlock.spsPointer;
- spBlock1.spID = 2;
- SGetCString(&spBlock1);
- return (char *)spBlock1.spResult;
- }
- else{
- Ptr p;
- p=NewPtr(1);
- p[0]=0;
- return p;
- }
- }
-
- #if 0
- flags The flags word in the driver’s DCE.
-
-
- //#include <NameRegistry.h>
- //#include <Drivers.h>
- #endif
-
- OSErr GDGestalt(GDHandle device,OSType driverGestaltSelector,unsigned long *driverGestaltResponsePtr)
- {
- int error;
-
- if(device==NULL || (*device)->gdRefNum==0) return statusErr;
- error=DriverGestalt((*device)->gdRefNum,driverGestaltSelector,driverGestaltResponsePtr);
- return error;
- }
-
- struct DriverGestaltParam {
- QElemPtr qLink;
- short qType;
- short ioTrap;
- Ptr ioCmdAddr;
- ProcPtr ioCompletion;
- OSErr ioResult;
- StringPtr ioNamePtr;
- short ioVRefNum;
- short ioCRefNum; /* refNum for I/O operation*/
- short csCode; /* == driverGestaltCode */
- OSType driverGestaltSelector;
- unsigned long driverGestaltResponse;
- };
- typedef struct DriverGestaltParam DriverGestaltParam;
- enum{kcsDriverGestalt=43};
- enum{kmDriverGestaltEnableMask=1L<<2};
-
- Boolean GDGestaltIsOn(GDHandle device)
- {
- AuxDCE **auxDCEHandle;
-
- if(device==NULL || (*device)->gdRefNum==0) return 0;
- auxDCEHandle=(AuxDCE **)GetDCtlEntry((*device)->gdRefNum);
- return (**auxDCEHandle).dCtlFlags & kmDriverGestaltEnableMask;
- }
-
- OSErr DriverGestalt(int refNum,OSType driverGestaltSelector,unsigned long *driverGestaltResponsePtr)
- /*
- Implements Driver Gestalt, documented in Designing PCI Cards and Drivers
- */
- {
- DriverGestaltParam param;
- int error;
- AuxDCE **auxDCEHandle;
-
- auxDCEHandle=(AuxDCE **)GetDCtlEntry(refNum);
- if(!((**auxDCEHandle).dCtlFlags & kmDriverGestaltEnableMask))return statusErr;
- param.ioCompletion=NULL;
- param.ioCRefNum=refNum;
- param.csCode=kcsDriverGestalt;
- param.driverGestaltSelector=driverGestaltSelector;
- param.driverGestaltResponse=0;
- error=PBStatus((ParmBlkPtr) ¶m,0);
- if(driverGestaltResponsePtr!=NULL) *driverGestaltResponsePtr=param.driverGestaltResponse;
- return error;
- }
-
- #if 0
- struct DriverType {
- Str31 nameInfoStr;
- NumVersion version;
- }
- typedef UInt32 DeviceTypeMember;
- typedef struct DriverType DriverType;
- typedef struct DriverType *DriverTypePtr;
- struct DriverOSRuntime {
- RuntimeOptions driverRuntime;
- Str31 driverName;
- UInt32 driverDescReserved[8];
- };
- typedef OptionBits RuntimeOptions;
- typedef struct DriverOSRuntime DriverOSRuntime;
-
- struct DriverDescription {
- OSType driverDescSignature;
- DriverDescVersion driverDescVersion;
- DriverType driverType;
- DriverOSRuntime driverOSRuntimeInfo;
- DriverOSService driverServices;
- };
- typedef struct DriverDescription DriverDescription;
- typedef struct DriverDescription *DriverDescriptionPtr;
-
- OSErr GetDriverName(GDHandle device,unsigned char *name);
-
- OSErr GetDriverName(GDHandle device,unsigned char *name)
- {
- long nameRegistryVersion;
- OSErr error;
- UnitNumber unit;
- DriverFlags flags;
- FSSpec driverFileSpec;
- RegEntryID regEntryID;
- CFragHFSLocator loc;
- CFragConnectionID fragmentConnID;
- DriverOpenCount openCount;
- DriverEntryPointPtr fragmentMain;
- DriverDescription driverDescription;
-
- name[0]=0;
- error=Gestalt('nreg',&nameRegistryVersion);
- if(!error){
- loc.u.onDisk.fileSpec = &driverFileSpec;
- error=GetDriverInformation((*device)->gdRefNum,&unit,&flags,&openCount,name
- ,®EntryID,&loc,&fragmentConnID,&fragmentMain,&driverDescription);
- }
- return error;
- }
- #endif
-
- unsigned char *GDName(GDHandle device)
- // Returns a pointer to the name of the driver (a pascal string).
- {
- VideoDriver *videoDriverPtr;
-
- if(device==NULL || (*device)->gdRefNum==0)return "\p";
- videoDriverPtr=GDDriverAddress(device);
- return videoDriverPtr->name;
- }
-
- char *GDNameStr(GDHandle device)
- // Returns the driver name as a C string.
- {
- unsigned char *sp;
- static char name[32];
-
- sp=GDName(device);
- memcpy(name,sp,sp[0]+1);
- return p2cstr((unsigned char *)name);
- }
-
- int GDVersion(GDHandle device)
- // Returns the version number of the driver. From the first word-aligned word after
- // the name string.
- {
- int version;
- unsigned char *bytePtr;
-
- if(device==NULL || (*device)->gdRefNum==0)return 0;
- bytePtr=GDName(device);
- bytePtr += 1+bytePtr[0]; /* go to end of Pascal string */
- bytePtr = (unsigned char *)((long)(bytePtr+1) & ~1); // round up to word boundary
- version = *(short *)bytePtr;
- return version;
- }
-
- VideoDriver *GDDriverAddress(GDHandle device)
- // Returns a pointer to the driver, whether in ROM or RAM.
- {
- AuxDCE **auxDCEHandle;
- VideoDriver *videoDriverPtr;
-
- if(device==NULL || (*device)->gdRefNum==0)return NULL;
- auxDCEHandle = (AuxDCE **) GetDCtlEntry((*device)->gdRefNum);
- if((**auxDCEHandle).dCtlFlags & dRAMBasedMask){
- /* RAM-based driver. */
- videoDriverPtr=*(VideoDriver **) (**auxDCEHandle).dCtlDriver;
- }
- else{
- /* ROM-based driver. */
- videoDriverPtr=(VideoDriver *) (**auxDCEHandle).dCtlDriver;
- }
- return videoDriverPtr;
- }
-
- /*
- ROUTINE: PatchMacIIciVideoDriver
- PURPOSE:
- It is unlikely that you will need to call this explicitly, because it is called
- automatically by GDGetEntries the first time it is invoked, and the sole purpose
- of this routine is to fix a driver bug that would cause a crash when called by
- GDGetEntries.
-
- The Mac IIci built-in video driver (.Display_Video_Apple_RBV1 driver, version 0)
- has a bug that causes it to crash if you try to do a cscGetEntries Status request.
- PatchMacIIciVideoDriver() will find and patch the memory-resident copy of the
- buggy driver. Only two instructions are modified, to save and restore more
- registers. This fix persists only until the next reboot. If the patch is
- successfully applied the version number is increased from 0 to 100, to
- distinguish it from versions 0 and 1.
-
- A returned value of 1 indicates success: the needed patch was applied, either now
- or previously. A return value of 0 indicates no patch was needed.
-
- This patch is based on a comparison of the version 0 and 1 drivers used by the
- Mac IIci and IIsi, respectively. The patch changes a pair of save and restore
- operations (MOVEM.L to and from the stack) to save and restore registers D1 and
- A1 as well as D4, A3, and A4. There are many other differences between versions
- 0 and 1 of the driver, but this change is enough to keep the version 0 driver
- from crashing when we attempt to read the clut by calling GDGetEntries.
-
- The only change that the Mac operating system could possibly notice is that,
- when we're done patching, we set the handle to be non-purgeable, since purging
- and reloading the driver would eliminate the patch.
-
- edward_de_Jong@bmug.org and Robert Savoy (SAVOY@RISVAX.ROWLAND.ORG) reported
- that their Mac IIci computers' built-in video driver is ROM-based, so
- PatchMacIIciVideoDriver was enhanced to deal with a ROM-based driver, by copying
- the driver into RAM, making that the active driver, and patching it. Robert
- Savoy reports that it works fine.
-
- An alternative, permanent, solution is described in the file "Video synch":
- upgrading to Apple's bug-free version 1 of the driver. However, that solution
- only works if the Mac IIci has more than one monitor.
-
- */
-
- int PatchMacIIciVideoDriver(void)
- {
- GDHandle device;
- short *w;
- AuxDCE **auxDCEHandle;
- Handle handle;
- enum{badVersion=0};
- int error;
- long value;
-
- error=Gestalt(gestaltQuickdrawVersion,&value);
- if(error || value<gestalt8BitQD)return 0; // need 8-bit quickdraw
- device = GetDeviceList();
- while(1) {
- if(device==NULL || (*device)->gdRefNum==0)return 0;
- if (!TestDeviceAttribute(device,screenDevice)
- || !TestDeviceAttribute(device,screenActive)){
- device=GetNextDevice(device);
- continue;
- }
- if(EqualString("\p.Display_Video_Apple_RBV1",GDName(device),1,1))
- switch(GDVersion(device)){
- case badVersion:
- break;
- case badVersion+100: // already patched
- return 1;
- default:
- return 0;
- }else{
- device=GetNextDevice(device);
- continue;
- }
- break;
- }
- auxDCEHandle = (AuxDCE **) GetDCtlEntry((*device)->gdRefNum);
-
- // Move ROM-based driver into RAM.
- if(!((**auxDCEHandle).dCtlFlags & dRAMBasedMask)){
- long bytes;
- VideoDriver *driver;
-
- driver=(VideoDriver *)(**auxDCEHandle).dCtlDriver;
- // Sometimes the word preceding the driver in ROM seems to be the
- // driver size, but not always, e.g. the built-in driver on the Mac IIsi.
- bytes=*((short *)driver-1);
- // Driver size unknown, guessing (generously) at twice the highest offset.
- bytes=driver->open;
- if(bytes<driver->prime)bytes=driver->prime;
- if(bytes<driver->control)bytes=driver->control;
- if(bytes<driver->status)bytes=driver->status;
- if(bytes<driver->close)bytes=driver->close;
- bytes*=2;
- // We know the Mac IIci driver size to be 1896
- // when ROM version is 124 rev. 1, but who knows for later ROMs?
- //bytes=1896;
- handle=NewHandleSys(bytes);
- if(handle==NULL)return 0; // Insufficient room on System heap.
- HLockHi(handle);
- BlockMove((Ptr)driver,*handle,bytes);
- (**auxDCEHandle).dCtlDriver=(Ptr)handle;
- (**auxDCEHandle).dCtlFlags |= dRAMBasedMask;
- }
-
- // Patch RAM-based driver.
- handle=(Handle)(**auxDCEHandle).dCtlDriver;
- w=*(short **)handle;
- if(w[0x51e/2]!=0x818 || w[0x590/2]!=0x1810 || w[0x2c/2]!=badVersion){
- printf("PatchMacIIciVideoDriver error.\n");
- return 0;
- }
- w[0x51e/2]=0x4858;
- w[0x590/2]=0x1a12;
- w[0x2c/2]+=100; // Change version number.
- if(w[0x51e/2]!=0x4858 || w[0x590/2]!=0x1a12){
- printf("PatchMacIIciVideoDriver error.\n");
- return 0;
- }
- HNoPurge(handle);
- return 1;
- }
-
- /*
- Received: 10/24
- From: Fernando Urbina, nano@apple.com
- To: Denis Pelli, denis@cns.nyu.edu
-
- The following is the information on the private call for the 7500 and the
- 8500 to disable waiting for VBL's and to change the time that we wait for
- the CLUT to settle after writing each entry in the CLUT. As shipped, the
- driver waits for 800 nanoseconds after writing each RGB triplet, to allow
- the hardware to increment the CLUT address.
-
- cscSetTimeDelays is used to set some flags and time delays used to write the
- CLUT. Use PBControl to issue the call, with the csParam[0] containing a pointer
- to a VDTimeDelay structure. Set the "validMask" field with the bits
- indicating which parameters you want to set.
-
- cscGetTimeDelays is used to examine the current values of the flags and time
- delays. Use PBStatus instead of PBControl. Set the "validMask" field
- with the bits indicating which parameters you want to get.
-
- The following is the definition of the fields of the VDTimeDelay struct:
-
- flags, bit 0: DontWaitForVBL flag: When false, it means that the driver should
- wait for a VBL before writing the CLUT. When true, the driver should NOT wait
- for a VBL.
-
- flags, bit 1: SetCLUTAddrRegTiming flag: When false, use the default timing.
- When true, use paramOne and paramTwo to specify the delay in nanoseconds.
-
- validMask: Specifies which bits in flags are valid. Bits are valid when
- corresponding bit position is 1.
-
- paramOne,paramTwo: When the SetCLUTAddrRegTiming bit of the validMask is set,
- then these fields specify the delay, in nanoseconds: nanoseconds.hi in paramOne
- and nanoseconds.lo in paramTwo. See Designing PCI Cards & Drivers for the
- Nanoseconds data structure.
-
- */
- enum{cscSetTimeDelays = 141}; // Used to set the different time delays
- enum{cscGetTimeDelays = 141};
- enum{gDontWaitForVBLMask=1,gSetCLUTTimingMask=2};
- #if PRAGMA_ALIGN_SUPPORTED || __MWERKS__
- #pragma options align=mac68k
- #endif
- struct VDTimeDelays{
- UInt32 flags;
- UInt32 validMask;
- UInt32 paramOne;
- UInt32 paramTwo;
- };
- typedef struct VDTimeDelays VDTimeDelays;
- #if PRAGMA_ALIGN_SUPPORTED || __MWERKS__
- #pragma options align=reset
- #endif
- OSErr GDSetTimeDelays(GDHandle device,VDTimeDelays *timeDelaysPtr);
- OSErr GDGetTimeDelays(GDHandle device,VDTimeDelays *timeDelaysPtr);
-
- OSErr GDSetDelay(GDHandle device,Boolean dontWaitForVBL,double nanoseconds)
- {
- OSErr error;
- VDTimeDelays timeDelays={0,0,0,0};
-
- timeDelays.validMask=gDontWaitForVBLMask;
- if(dontWaitForVBL)timeDelays.flags=gDontWaitForVBLMask;
- else timeDelays.flags=0;
- if(IsFinite(nanoseconds)){
- timeDelays.flags|=gSetCLUTTimingMask;
- timeDelays.validMask|=gSetCLUTTimingMask;
- timeDelays.paramOne=nanoseconds/0x10000/0x10000;
- timeDelays.paramTwo=nanoseconds-(double)timeDelays.paramOne*0x10000*0x10000;
- }else timeDelays.paramOne=timeDelays.paramTwo=0;
- error=GDSetTimeDelays(device,&timeDelays);
- return error;
- }
- OSErr GDGetDelay(GDHandle device,Boolean *dontWaitForVBLPtr,double *nanosecondsPtr)
- {
- OSErr error;
- VDTimeDelays timeDelays={0,0,0,0};
-
- timeDelays.validMask=gDontWaitForVBLMask|gSetCLUTTimingMask;
- error=GDGetTimeDelays(device,&timeDelays);
- if(error)return error;
- if(dontWaitForVBLPtr!=NULL){
- if(timeDelays.flags&gDontWaitForVBLMask) *dontWaitForVBLPtr=1;
- else *dontWaitForVBLPtr=0;
- }
- if(nanosecondsPtr!=NULL)
- *nanosecondsPtr=(double)timeDelays.paramTwo+(double)timeDelays.paramOne*0x10000*0x10000;
- return error;
- }
- OSErr GDSetTimeDelays(GDHandle device,VDTimeDelays *timeDelaysPtr)
- {
- OSErr error;
- long stackSpace;
-
- stackSpace=StackSpace();
- if(device==NULL || (*device)->gdRefNum==0 || timeDelaysPtr==NULL) return controlErr;
- error=GDControl((*device)->gdRefNum,cscSetTimeDelays,(Ptr)timeDelaysPtr);
- stackSpace=StackSpace();
- return error;
- }
- OSErr GDGetTimeDelays(GDHandle device,VDTimeDelays *timeDelaysPtr)
- {
- OSErr error;
- long stackSpace;
-
- stackSpace=StackSpace();
- if(device==NULL || (*device)->gdRefNum==0 || timeDelaysPtr==NULL) return statusErr;
- error=GDStatus((*device)->gdRefNum,cscGetTimeDelays,(Ptr)timeDelaysPtr);
- stackSpace=StackSpace();
- return error;
- }
- Boolean IsPCIMac(void)
- {
- static Boolean pci,firstTime=1;
-
- if(firstTime){
- long templong;
- int error;
- #define gestaltNameRegistryVersion 'nreg' // support for old versions of Gestalt.h
- error=Gestalt(gestaltNameRegistryVersion,&templong);
- pci=(error==0); // are there PCI slots?
- firstTime=0;
- }
- return pci;
- }
- void GDRestoreBlackAndWhite(GDHandle device)
- // Restore the first & last clut entries to white and black.
- {
- short clutSize;
- int error;
- ColorSpec white={255,0xffff,0xffff,0xffff},black={0,0,0,0};
-
- clutSize=GDClutSize(device);
- switch((**device).gdType){
- case clutType:
- error=GDSetEntries(device,0,0,&white);
- error=GDSetEntries(device,clutSize-1,0,&black); // Fixed 3/4/96
- break;
- case directType:
- error=GDDirectSetEntries(device,0,0,&black);
- error=GDDirectSetEntries(device,clutSize-1,0,&white); // Fixed 3/4/96
- break;
- default:
- break;
- }
- }
-