The Advanced Amiga Chip set (AA) redefines graphics performance on the Amiga by adding many new display modes, new features and more color to the Amiga platform. This article presents an overview of how the new V39 graphics library has implemented theses new features in the system software.
In V39, the graphics library has changed in the following areas:
The original Amiga graphics library exposed many device-dependent details to the application programmer. Because of this, introduction of new graphics devices has been slowed, and application support of new features has been delayed. To reverse this trend, no features have been added to the new graphics system which cannot be kept for the future. Thus, when newer graphics systems are introduced, system software will need fewer changes, and applications will be ready to automatically use new capabilities. Thus, parameters such as number of bits per pixel, resolution, color palette size, etc., are either variable or have been made very large.
The AA chips are register level compatible with the old and ECS chips at boot up time. However, when new AA modes are enabled and displayed, and a game then takes over the screen display without informing the OS of it, some registers may be in incompatible settings.
Two approaches will reduce this:
For bootable games that want AA features, use the V39 graphics function SetChipRev(). This lets you upgrade the Amiga to be any chip revision you need, and handles the extra house-keeping that graphics needs to operate the selected chipset (such as updating the graphics database). The only restriction is that it is not possible to downgrade the setting from AA down to ECS or A.
This release of graphics.library will attempt to ease the (future) transition to Retargetable Graphics. New functions are provided to do some operations in a more device-independent manner. This will help when we have to support foreign graphics devices, more than 8 bits per pixel, chunky pixels, and true-color displays.
These new "Get/Set" functions will allow device independent access to fields in the RastPort structure which were only previously manipulable by direct structure access.
VOID SetAPen(rp, pen) Sets the current APen value
ULONG GetAPen(rp) Return current APen value
VOID SetBPen(rp, pen) Sets the current BPen value
ULONG GetBPen(rp) Return current BPen value
VOID SetDrMd(rp, mode) Sets the current DrawMode
ULONG GetDrMd(rp) Return current DrawMode
VOID SetOPen(rp,c) Was a macro. Now use the SetOutlinePen()
function, or the SafeSetOutlinePen() macro.
ULONG GetOPen(rp) Return current area outline pen
VOID SetWrMsk(rp,m) Was a macro. Now use the SetWriteMask()
function, or the SafeSetWriteMask() macro.
ULONG GetWrMsk(rp) Description of this function is left as an
exercise for the reader.
VOID SetABPenDrMd(rp,apen,bpen,drmd)
Sets the APen, BPen, and DrawMode for a RastPort. Faster than
separate calls.
VOID SetRPAttr(rp,taglist)
You asked for it so here it is. Lets you set many of the
RastPort attributes with one tag-based call. Here are the attributes
currently supported:
RPTAG_Font Font for Text() RPTAG_SoftStyle style for text
(see graphics/text.h)
RPTAG_APen Primary rendering pen
RPTAG_BPen Secondary rendering pen
RPTAG_DrMd Drawing mode (see graphics/rastport.h)
RPTAG_OutLinePen Area Outline pen
RPTAG_WriteMask Bit Mask for writing.
RPTAG_MaxPen Maximum pen to render (see SetMaxPen())
VOID GetRPAttr(rp, taglist)
No prizes for guessing what this does. It supports the extra tag RPTAG_DrawBounds. This tag is passed with a pointer to a rectangle structure. The returned rectangle structure will contain the bounds of the clipping regions inside the RastPort. This can be used to optimize drawing and refresh.
The color palette in AA is different in a lot of ways from the ECS one:
All colors are now specified as 32 bit left-justified fractions, and are truncated based upon the number of bits that the hardware is capable of displaying.
There are now ...RGB32() functions to replace the ...RGB4() functions. These all work in 32-bits per gun, irrespective of the device the colors are intended for. Devices that cannot handle the color resolutions will truncate the colors to the most significant n bits. That is why it is important to duplicate the most significant n bits throughout the 32-bit resolution. For example, pure white should be treated as:
R = 0xffffffff, G = 0xffffffff, B = 0xffffffff
and not
R = 0xf0000000, G = 0xf0000000, B = 0xf0000000
The new color palette functions allow for multiple applications to coordinate their access to the palette. This allows applications to, for instance, dynamically remap pictures to match the color palette of the Workbench screen, display animations in windows, etc.
ObtainPen() will attempt to obtain a free palette entry for use by your program, and then set the pen number to the RGB value you specify. A pen can be either shared or exclusively for your own use. If shared, then you should not modify the RGB value of the pen once the pen is obtained, because other applications may use that same pen, and will be relying on its color.
ObtainBestPen() is a tag-based function that will attempt to find the pen in the ColorMap which is closest to the specified RGB value, and then return a shared pen to you. There are (currently) four levels of precision to which the RGB value must match. PRECISION_EXACT asks for an exact match of the RGB value. The other three are, in descending order of precision, PRECISION_IMAGE, PRECISION_ICON, and PRECISION_GUI. If there is no pen in the ColorMap with the required RGB value to the specified precision, and there are unallocated pens, then a new pen is reserved as shared, and its RGB value set to the value you requested.
Note, there is no way to physically stop you from changing the colors of shared pens, but it's just not done, so don't do it. Pens obtained either with ObtainPen() or ObtainBestPen() should be released back to the system with ReleasePen() when no longer used.
All the palette-sharing functions require a struct PalExtra to be attached to the ColorMap. This is done automatically for all Intuition screens, but if you are not using Intuition, then you will need to call AttachPalExtra() yourself. This allocates and attaches a PalExtra structure to the ColorMap. The PalExtra is deallocated by the FreeColorMap() function.
FindColor(cm,r,g,b,maxcolor) lets an application find the "closest" color to a given RGB value, independently of palette sharing. In fact, using SetRGB32CM and FindColor, you can perform color matching which is not associated with a display at all.
These function exist because the new AA chips have alignment restrictions in high bandwidth modes. Changing InitBitMap() and AllocRaster() to obey these restrictions would have been very incompatible. Bitmaps created by AllocRaster with a multiple of 32 or 64 pixels per line will be compatible with high fetch modes (2x or 4x respectively). Incompatible ones will fall back to 1x mode, if 1x mode is capable of displaying the screen.
AllocBitMap() allocates an entire bitmap structure, and the display memory for it. AllocBitMap() allows you to use more than 8 planes, and also allows you to specify another bitmap pointer, thus telling the system to allocate the bitmap to be "like" another bitmap. A bitmap allocated in such a matter may be able to blit to this bitmap faster. Such a bitmap may be stored in a foreign device's local memory. Do not assume anything about the structure of a bitmap allocated in this manner. The size of a bitmap structure is subject to change in future graphics releases. Thus, you should use AllocBitMap()/FreeBitMap() for your raster allocation.
Graphics sprite functions (MoveSprite()) have been extended to understand large sprites, selectable sprite pixel resolution, and movement of scan-doubled sprites. Sprite positioning is no longer rounded down to lo-res pixel resolution. Applications will no longer have to "know" about the hardware-dependent format of sprite data.
The new sprite functions work with an ExtSprite structure, which is obtained with the tag-based AllocSpriteData() function. This function allows you to specify a BitMap for the image of the sprite, and tags to specify scaling factors to apply to the BitMap. The returned ExtSprite structure is then passed to GetExtSprite(), which is the V39 equivalent of the old GetSprite() function. There is no equivalent FreeExtSprite(0 function; FreeSprite() does the trick. The ExtSprite allocated with AllocSpriteData() is freed with FreeSpriteData().
The AA chip set imposes some limitations on sprites:
All the AA sprite features are available through new tags for VideoControl():
VTAG_SPEVEN_BASE_SET/GET
This sets the base color number of the even numbered sprites. The AA chip set allows odd numbered and even numbered sprites to use the colors of different 16-color banks, as opposed to the previous chip sets where all sprites used colours 16-31. Legal values to set the base are 0-255, but will be rounded down to the nearest multiple of 16.
VTAG_SPODD_BASE_SET/GET
As VTAG_SPEVEN_BASE_SET/GET, only for the odd numbered sprites. For example, if the following tag list is passed to VideoControl():
struct TagItem[] = { {VTAG_SPEVEN_BASE_SET, 32},
{VTAG_SPODD_BASE_SET, 144}, {TAG_DONE}, };
then the sprites use the following colors:
Sprite | Colors |
---|---|
0 | 32 (transparent),33,34,35 |
2 | 36 (transparent), 37,38,39 |
4 | 40 (transparent), 41,42,43 |
6 | 44 (transparent), 45,46,47 |
1 | 144 (transparent), 145,146,147 |
3 | 148 (transparent), 149,150,151 |
5 | 152 (transparent), 153,154,155 |
7 | 156 (transparent), 157,158,159 |
[Attached sprites use the palette settings of the odd numbered sprites.]
Normally, there are only (2 << depth) colours in a ColorMap (with the exception that Intuition screens always have a minimum of 32 colours). If you wish to set the sprite's colors to use pens that are outside of this range, then you should use the VTAG_FULLPALETTE_SET tag, which specifies that the ColorMap should contain entries for all possible colors (256). Therefore, the colors of these entries can be set with the usual ...RGB32() functions. Not setting VTAG_FULLPALETTE_SET in this case may cause unpredictable colors and enforcer hits.
VTAG_SPRITERESN_SET/GET This allows you to set all the sprites in the ViewPort to one of 5 resolutions. SPRITERESN_140NS: All sprites have 140ns pixels. SPRITERESN_70NS: All sprites have 70ns pixels. SPRITERESN_35NS: All sprites have 35ns pixels. SPRITERESN_DEFAULT: All sprites have the Intuition default resolution. SPRITERESN_ECS: Compatible with ECS resolutions; 140ns, except in 35ns display pixel modes (SuperHires), where the sprite pixels are 70ns.VTAG_DEFSPRITERESN_SET/GET
For setting the default sprite resolution, as used by SPRITERESN_DEFAULT.
VTAG_BORDERSPRITE_SET/GET/CLR:
This sets the bordersprite option in the AA chipset for the ViewPort, which allows sprites to appear in the borders outside of the normal display window (DisplayClip), i.e., the area that is normally color 0. However, this does not apply to the horizontal blanking area.
VTAG_PF1_TO_SPRITEPRI_SET/GET:
All revisions of the Amiga chips have allowed the priorities of sprites to playfield to be set. Usually, the priority is such that the sprites always appear in front of the playfield. There is an entry in the ViewPort structure for altering this priority, but V39 provides this tag in preference to writing to the ViewPort structure.
VTAG_PF2_TO_SPRITEPRI_SET/GET:
As VTAG_PF1_TO_SPRITEPRI_SET/GET, only for playfield 2. On the Amiga, playfield 2 is the default playfield, and playfield 1 is only used in DualPlayfield modes!
The graphics database has been extended where necessary for AA information, and these changes are limited to the DisplayInfo structure. The DisplayInfo->PaletteRange is only one WORD long, which is insufficient for the AA 24-bit colour resolution, and so has been superceded by three new entries called RedBits, BlueBits and GreenBits. These are one BYTE each, and show how many bits of precision is available for each colour gun. 255 bits each for red, green and blue should be enough for the foreseeable future (pun intended).
Some new DIPF_IS flags were added to the database, providing more information about each display mode ID. DIPF_IS_SPRITES_ATT shows the mode supports attached sprites. The 35ns display modes on ECS could not support them. DIPF_IS_SPRITES_CHNG_RES shows that the mode supports sprites that can change resolution, and so the VTAG_SPRITERESN_SET VideoControl() tag will work on ViewPorts in this mode. DIPF_IS_SPRITES_BORDER shows that this mode supports border sprites, so the VTAG_BORDERSPRITE_SET VideoControl() tag will work on ViewPorts in this mode. DIPF_IS_SCANDBL shows that this mode is scandoubled (each display line is repeated once), so that half as many lines take up the same physical area on the monitor. There should be no need for you to look at this bit. DIPF_IS_SPRITES_CHNG_BASE shows that this mode supports sprite base colour offset changing, so that the VTAG_SPODD/SPEVEN_BASE_SET VideoControl() tag will work on ViewPorts in this mode. DIPF_IS_SPRITES_CHNG_PRI shows that this mode supports changing the playfield to sprite priority, so that the VTAG_PF2/PF1_TO_SPRITEPRI_SET VideoControl() tag will work on ViewPorts in this mode. DIPF_IS_DBUFFER shows that this mode will work with the double-buffering Chan geVPBitMap() function. You should check this flag before using the double-bufferi ng functions on the ViewPort. DIPF_IS_PROGBEAM shows that this mode is a programmed beam-sync mode. DIPF_IS_FOREIGN shows that this mode is not native to the Amiga chip set. Currently, no mode IDs will have this flag set, but under RTG many 3rd party display devices will. You may want to start checking for this flag now.With the plethora of new display modes that are available under V38 and V39, it is now becoming harder and harder for both the application writer and the end user to know which display mode ID they need to use. This will be especially true under RTG when the application writer will have no way of knowing all the possible display mode IDs that are available on third party display devices. A function was added for V39 to alleviate this problem, and provide a means by which the system can calculate the best mode ID to use given a number of requirements, called BestModeID(). It takes the following tags:
BIDTAG_DIPFMustHave
The DIPF_ flags that this display mode ID must have set. Default is NULL, so there is no preference.
BIDTAG_DIPFMustNotHave
The DIPF_ flags that this display mode ID must not have set. For example, you may wish to ensure that only native Amiga modes are considered, so use BIDTAG_DIPFMustNotHave with DIPF_IS_FOREIGN. The default value is defined as SPECIAL_FLAGS, which is (DIPF_IS_DUALPF | DIPF_IS_PF2PRI | DIPF_IS_HAM | DIPF_IS_EXTRAHALFBRITE) so you may need to OR your particular requirements with SPECIAL_FLAGS.
BIDTAG_ViewPort An initializes ViewPort for which a mode ID is sought. For example, to find an interlaced version of a ViewPort: ID = BestModeID( BIDTAG_ViewPort, ThisViewPort, BIDTAG_MustHave, DIPF_IS_LACE, TAG_END); BIDTAG_NominalWidth BIDTAG_NominalHeight Together make up the aspect ratio of the desired mode ID. If specified, will override the Width and Height of the ViewPort passed in BIDTAG_ViewPort, or the NominalDimensionInfo of the ID passed in BIDTAG_SourceID. Defaults to 640x200. BIDTAG_DesiredWidth BIDTAG_DesiredHeight Nominal width and height of the returned mode ID. BIDTAG_Depth Mode ID must support at least this many bitplanes. Defaults to vp->RasInfo-> BitMap->Depth of the ViewPort passed in BIDTAG_ViewPort, or 1. BIDTAG_MonitorID The returned mode ID must belong to this monitor family. BIDTAG_SourceID BestModeID() will use characteristics of this mode ID, and override some of the characteristics with the other values in the taglist. BIDTAG_RedBits BIDTAG_BlueBits BIDTAG_GreenBits The mode ID must support at least these many bits for each color gun. Defaults to 4 bits each, so A2024 modes will not be considered. As an example of its use, here is a portion of the code for the V39 CoerceMode() function (which is used by Intuition when coercing screens):
ULONG CoerceMode(struct ViewPort *vp, ULONG MonitorID, ULONG Flags) {
...
/* Coerce the ViewPort vp to the best fit ModeID in the monitor
* MonitorID.
*/
must = NULL;
mustnot = SPECIAL_FLAGS;
tag[t].ti_Tag = BIDTAG_ViewPort;
tag[t++].ti_Data = vp;
tag[t].ti_Tag = BIDTAG_MonitorID;
tag[t++].ti_Data = MonitorID;
if (GetDisplayInfoData(NULL, (APTR)&dinfo,
sizeof(struct DisplayInfo), DTAG_DISP, ID))
{
must = (dinfo.PropertyFlags & SPECIAL_FLAGS);
mustnot = (SPECIAL_FLAGS & ~must);
if ((Flags & AVOID_FLICKER) && (!(dinfo.PropertyFlags &
DIPF_IS_LACE)))
{
/* we don't want lace if AVOID_FLICKER is set,
* and this ViewPort is not naturally laced.
*/
mustnot |= DIPF_IS_LACE;
}
tag[t].ti_Tag = BIDTAG_RedBits;
tag[t++].ti_Data = dinfo.RedBits;
tag[t].ti_Tag = BIDTAG_GreenBits;
tag[t++].ti_Data = dinfo.GreenBits;
tag[t].ti_Tag = BIDTAG_BlueBits;
tag[t++].ti_Data = dinfo.BlueBits;
}
tag[t].ti_Tag = BIDTAG_DIPFMustNotHave;
tag[t++].ti_Data = mustnot;
tag[t].ti_Tag = BIDTAG_DIPFMustHave;
tag[t++].ti_Data = must;
tag[t].ti_Tag = TAG_DONE;
return(BestModeIDA(tag));
}
As another example, consider an IFF display program with a HAM image,
to be displayed in the same monitor type as the Workbench ViewPort.
ID = BestModeID(BIDTAG_NominalWidth, IFFImage->Width,
BIDTAG_NominalHeight, IFFImage->Height,
BIDTAG_Depth, IFFImage->Depth,
BIDTAG_DIPFMustHave, DIPF_IS_AM,
BIDTAG_MonitorID, (GetVPModeID(WbVP) & MONITOR_ID_MASK),
TAG_END);
The definitions of the display mode ID keys have been moved from <graphics/displayinfo.h> to a new <graphics/modeid.h> file.
The include file
Promotion is a software solution for the lack of hardware deinterlacing circuitry on the AA machines. With the promotion feature enabled in Icontrol, the default monitor (NTSC on NTSC machines, PAL on PAL machines), becomes DblNTSC on NTSC machine and DblPAL on PAL machines. There are a number of advantages and gotchas with this approach.
One advantage is that the graphics database is always truthful. Any enquiries about a default monitor mode ID will yield information relevant to whatever the default monitor happens to be at the time. This should not be a problem for any code written for V37 onwards, as the default monitor has always been either NTSC or PAL; now, there are just more possibilities.
Another advantage is that V39-aware software that requires NTSC or PAL modes (e.g., video titling software), can now get such modes using specific NTSC or PAL mode IDs.
Here is a list of "gotchas" (that is, things to watch out for if you want display mode promotion to work correctly).
Interleaved screens have been added. These use a different layout of the graphics data in order to speed rendering operations and eliminate the annoying "color-flash" problem which is the hallmark of planar (as opposed to "chunky") display architectures. Set the BMF_INTERLEAVED flag when calling AllocBitMap().
Double buffering functions have been added. These allow applications to display very smooth, synchronized animation in fully an efficient "Intuition-friendly" manner. Call AllocDBufInfo() to allocate and initialize the DBufInfo structure, which is then passed to ChangeVPBitMap(). The double-buffering functions return up to two different types of messages. The first (dbi_SafeMessage) tells your program when it is safe to write to the old BitMap. The second (dbi_DispMessage) is sent when it is safe to call ChangeVPBitMap() again and be certain the new bitmap has been seen for at least 1 field. The autodocs for AllocDBufInfo() has example code showing how to safely double buffer with ChangeVPBitMap().
The DBufInfo structure should be freed with the FreeDBufInfo() function.
Due to the extra colours that need to be loaded in deeper AA screens, the gap between screens can now be greater than the three lines that Intuition traditionally kept. In fact, the number of lines between screens is variable, depending on the screen type and depth. A new function CalcIVG() (CalcInterViewPortGap) has been added to calculate the number of lines required by the copper to execute all the copper instructions before the display window is opened. Note however that CalcIVG() returns the true number of lines (rounded up to the next whole line) needed in ViewPort resolution units, but Intuition still maintains a gap of at least three lines between Screens. Therefore, when calling CalcIVG() to position screens in an Intuition environment, use the result of MAX((laced ? 6 : 3), CalcIVG(v, vp)).
There is one other caveat with respect to CalcIVG(). This function works by counting the number of copper instructions in the ViewPort->DspIns list, which is set up by MakeVPort(). If an Intuition screen is opened behind, then MakeVPort() is not called on that screen's ViewPort until it first becomes visible, so calling CalcIVG() with that screen's ViewPort will yield a result of 0.
Some operations have been sped up: RectFill() has been rewritten, WritePixel() uses the CPU (3x speedup) ScrollVPort is 10 times faster, and other optimizations.
There is a big bug in the V37-V39 graphics hash-table code, which is
used to associate a ViewExtra with a View; namely, only 8 Views can
have ViewExtras attached to them. This has been fixed in the latest
SetPatch and Kickstart.
ScrollVPort() and ChangeVPBitMap() have problems with 8-bit HAM mode.
This has been SetPatch'ed.
Many other outstanding bugs have been fixed for V39.
Some features that are planned for Release 3.1: