Graphics


Writing Portable TIGA Code

Tom Friend


Tom is the president of ATC Graphics Company, a software developer specializing in graphics device drivers for CAD applications and the X Window System. Tom has been involved in the computer graphics world since the late 70s. You can reach him at (206)297-4648. email: ... sco!atcgrfx!tomf.

While TIGA was designed to be a portable grapics interface, in practice there are always problems in porting an application from one machine to another.

I've written device drivers that allow TIGA to work with CAD applications such as VersaCAD Design, Generic CADD, and Microstation. In these environments, the driver code must work across a wide variety of platforms and TIGA devices. These platforms are always MS-DOS, but could be anything from 8088-to 486-based. This article will help explain some of the techniques of portable TIGA design. Many of the examples used in this article were taken from a VersaCAD driver originally written in 1988.

Background

TIGA, the Texas Instruments Graphics Architecture is a software interface and toolkit developed by TI to support their TMS34010 graphics chip. The 34010 or GSP (Graphics System Processor) is a general-purpose, 32-bit microprocessor that has a mix of general-purpose instructions and graphics-oriented instructions.

TI originally developed the assembler, compiler, and debugger tools for the GSP, and left the actual communications scheme up to the hardware vendors. Consequently, each graphics board vendor had to invent their own library of graphics functions and develop device drivers for every common device.

In 1988 TI released their first attempt at a standard communications scheme and graphics library. This release (version 0.50) had bugs and other shortcomings, but was a step in the right direction.

In spring of 1989, TI released version 1.0 of the TIGA interface. At the time of release, I was assured that all the code our company had written to the TIGA 0.50 standard would be upgraded with "a simple re-compile". Yeah, right... Working with one driver package to learn TIGA all over again, it took me four days to get light back on the screen, and another week to get the application fully debugged and polished.

Later that summer TI again released an upgrade to TIGA, and the version number went to 1.1 — an incremental upgrade. Once again my firm was promised compatibility with "a simple re-compile". This time the "simple re-compile" only required about three hours of changes to each TIGA module.

Basic Guidelines

The most basic principle of working with device-independent graphics code is: no magic numbers. Unlike other graphics standards that draw into a virtual space, TIGA deals with the real device resolution. All graphics calls must be scaled to the capabilities of the installed TIGA device.

Before you can begin using the drawing functions, you must query the TIGA device for its capabilities, its resolution, and the number of colors displayable (see Listing 1) . Even though TIGA will clip intelligently under certain initialization conditions, the conservative programmer will also set clipping limits and enable clipping as a precaution.

The screen origin for TIGA is the top-left corner. Thus, if your program draws with the bottom left corner as 0,0, you must invert the y-axis portion of all drawing commands sent to TIGA. Listing 2 shows how to draw a polygon, while inverting the y-axis (converting from bottom-origin to top-origin).

TIGA boards come in many flavors, and not all have what would be considered the basic essentials. Implementing look- up tables (LUTs or palettes) is an option, and not all boards have such capabilities. Also, you must consider how your code will run on monochrome screens, as these are very popular in the desktop publishing arena.

Unless you need an exact character set, it is best to use the default character font. TIGA allows characters to be drawn in arbitrary positions (without regard for row and column constraints) on the graphics screen. The font information structure will give you the dimensions of the font, which you should use to calculate the size of text windows.

Development Environment

The TIGA spec allows for three types of functions; core functions, TIGA-extended primitives, and user-extended primitives. Core primitives are always available to the programmer, a combination of TIGA-extended and user-extended primitives may also be available, depending upon how the programmer initializes the TIGA environment.

Core functions allow the application to query TIGA about its capabilities, and to modify the environment by installing TIGA-defined extensions (with the install_primitives() function) and user-defined extensions (with the install_rlm() and install_alm() functions). The install_xxx functions load a 34010 object code file into the instruction RAM of the TIGA board, linking the relocatable modules so they can communicate with the core code.

Extended Primitives?

The TIGA developer's first big design issue is often whether to use standard TIGA-extended primitives or write extensions. Quite often your application's memory needs will determine the answer.

In order to use the extended primitives, you must be able to install them (with a call to install_primitives()). Installing the extended primitives requires 70 - 100K of free RAM, since the TIGA extended primitives are in a Relocatable Load Module (RLM) format. Linking the TIGA relative symbols requires a gread deal of memory. Thus, you must wait until after calling install_primitives() to malloc all the memory needed by your application.

If you cannot use the extended primitives, as in the case of a device driver, you must create your own. For custom primitives, memory isn't an issue because they are loaded as an Absolute Load Module — the linking is trivial and requires no heap space.

Custom primitives have other advantages: reduced memory usage for both the TIGA device and the PC, and potentially enhanced performance. By writing your own primitives, you can move the bulk of the parsing code into the ALM, along with the drawing functions. Now the driver is smaller (less code and data), and faster, due to the extra parallelism achieved.

You can approach this goal incrementally if you begin by writing the driver to use the extended primitives, and when fully debugged, move as much functionality as possible into the ALM.

Gotchas And Work-Arounds

Often it is desirable to have a realmode device interface that works with protected-mode DOS applications. For example, the Phar Lap DOS conflicts with the TIGA interrupt usage. Phar Lap takes over interrupts 0x71 through 0x7f and TIGA's default interrupt is Ox7f. In order to use TIGA in this environment, you must change the TIGA environment variable prior to running the TIGACD.EXE communications driver that will tell TIGACD to use an alternate interupt. This command (see Figure 1) must be in the autoexec.bat file before the TIGA communications driver (TIGACD.EXE) is installed. Device independent code should avoid calling palette functions from custom primitives. For example, in one recent project, I wanted to load the LUT from the custom primitives to conserve data segment space. Placing the LUT constants into the ALM would have made the TSR-based driver 768 bytes smaller (256 colors * 3). Unfortunately this proved unportable because the core primitive functions set_palet(), and set_palet_entry() are based upon receiving red, green and blue values as unsigned chars (range 0-255), while the equivalent graphics library functions have device dependent values. The TI documentation calls these palette functions heavily device dependent.

Drawing circles with the TIGA-extended primitives can present their own set of problems, too. Many CAD and drawing packages must draw circles with patterns, and so does MS- Windows. Unfortunately the pattern function is incompatible between the two. In Windows, the driver must be able to draw circles with an area pattern. That is, the circle is drawn as if there was a piece of window screen acting as a pattern mask.

In some CAD device drivers (like VersaCAD), the circle draw function must be able to use the line pattern. The circle drawn would appear as if drawn with a patterned wheel. The work around involves writing your own ptn_oval() function.

Many of you are familiar with using read and write masks to preserve bit planes during graphics operations. If you want to protect plane 0, you would use a write mask of 0xfe, right? Not in TIGA. The mask value could be 0x0001, 0x0101, 0x1111, or 0x5555, depending upon whether the device has 16, 8, 4, or 2 bit planes total. You can work around this deficiency with the code in Listing 3.

Usually, the external primitives can be loaded outside of a TIGA application. This practice allows the install_primitives() function to execute much faster, since the code has already been installed and saves the 70+ KB link overhead. Unfortunately there are certain TIGA boards that will always reload the TIGA extended primitives.

The Verticom MX series are nice TIGA cards. They have a full VGA with separate video memory, support monitors from 640 x 480 to 1024 x 768, and also support DGIS and AI. I started a project using this card, and when I switched to another, found out about the primitive reloading problem. Because the MX uses a VGA chip set to provide console support, the primitives could remain loaded at all times, masking a portability problem that showed up with a different set of TIGA cards.

The Wyse 7190 is a 1280 x 960 monochrome TIGA card with CGA console support. I was very anxious to see my driver run this high-res card, and immediately tried it upon receipt of same. It wouldn't run at all, and didn't seem to initialize. Subsequent debugging revealed that the install_primitives() function was always attempting to reload the primitives, even when they had been loaded prior to my driver being invoked. This posed a problem, as I had no extra memory available to load the primitives, (remember, you need more than 70K) and the function was returning a failure code indicating that it had no memory available.

Further investigation revealed that the Wyse card was using the 34010 to provide CGA emulation, and that whenever the emulation was running, all the external primitives and the general TIGA environment are trashed. Since there is no way to tell if this has happened, I had to take the conservative approach that the graphics device was completely reset each time I switched to graphics mode. This also meant that I had to re-write the driver to use a custom set of primitives.

This card's architecture created other problems. Because the TIGA environment was trashed each time I toggled between alpha and graphics mode, each switch was also resetting the clipping, drawing colors and op, and transparency modes. Once I took the defensive posture of always restoring my entire graphics environment on every mode switch to graphics, the driver worked correctly.

To be fair to Wyse, the problem originated at TI. When designing the TIGA interface, TI failed to provide for the possiblity that a TIGA device might also be providing console emulation.

Conclusion

Overall, TIGA is a very good graphics interface that was obviously designed for use in a C environment. Once a simple graphics program has been developed and debugged to get the feel of the interface, very large tasks can be tackled with complete confidence. Like the TI hype says, the power lies in its extensibility.

References

To obtain the following materials, write to: TI Semiconductor Group, SC-9042, PO Box 809066, Dallas, TX 75380-9066, or call (800) 336-5236 ext. 700. Outside the U.S., call (214)-995-6611 ext. 700.

TIGA-340 Interface User's Guide

TMS34010 Math/Graphics Function Library User's Guide

TMS340 Family Code Generation Tools User's Guide

The Invisible Text Bug