This is a fast framebuffer-level graphics library for linear 1, 2, 3 and 4 byte-per-pixel modes (256-color, hicolor, truecolor). It uses a limited number of functions from svgalib (libvga) for low-level hardware communication (the library is included in the svgalib shared image). In particular, svgalib maps the 64K VGA frame buffer window, and this library directly addresses the buffer. For SVGA modes that use more than 64K of screen memory, SVGA paging is required when writing to the physical screen; this is done automatically for most functions (at a certain cost). Alternatively, any number of virtual screens of any type in system memory can be used, which can then be copied to the physical screen. There is also support for 4 bytes per pixel framebuffers (and copying them to a 3 bytes per pixel context), and limited planar 256 color mode support (copyscreen, aligned putbox). The planar 256 color modes (available on all VGA cards) can now be used with a virtual screen, which is copied to the physical screen (with optional page-flipping). Bitmaps are raw, with one (or more) bytes per pixel (like pixmaps in X), stored in row-major order. They are usually manipulated with the getbox and putbox functions. A graphics context is just a structure that holds the size of the associated graphics screen, how it is organized, clipping status etc. You can define a custom virtual (system memory) graphics context of any size with the setcontextvirtual function. All operations work on the current context. Any questions, bug-reports, additions, suggestions etc. are welcome. Functions (all have a "gl_" prefix): - simple line drawing setpixel( int x, int y, int c ) Draw a single pixel at position (x, y) in color c. The lower 8, 15, 16 or 24 bits of the color are significant, depending on the number of colors the current mode supports. setpixelrgb( int x, int y, int r, int g, int b ) Draw a single pixel at (x, y) with color components r, g, and b, ranging from 0 to 255. In 256 color mode, only meaningful if the RGB palette is set (setrgbpalette). int getpixel( int x, int y ) Returns color of pixel at position (x, y). getpixelrgb( int x, int y, int *r, int *g, int *b ) Store color components from pixel at (x, y) ranging from 0 to 255, into integers pointed to by r, g and b. int rgbcolor( int r, int g, int b ) Returns pixel value that corresponds with the given color components. Used by setpixelrgb. line( int x1, int y1, int x2, int y2, int c ) Draw a line from (x1, y1) to (x2, y2) inclusive in color c. hline( int x1, int y, int x2, int c ) Draw a horizontal line from (x1, y) to (x2, y) in color c. circle( int x, int y, int r, int c ) Draw a circle of radius r in color c. - box (bitmap) functions fillbox( int x, int y, int w, int h, int c ) Screen position (x, y), box size (w, h). Fill a rectangular area of the screen with a single color. getbox( int x, int y, int w, int h, void *dp ) Bitmap data pointer dp. Bitmaps are in row-major order. Copy a rectangular bitmap from the screen to a buffer. putbox( int x, int y, int w, int h, void *dp ) Bitmap data pointer dp. Copy a bitmap to a rectangular area of the screen. putboxpart( int x, int y, int w, int h, int bw, int bh, void *bp, int xo, int yo ) Copy a partial bitmap to the screen. (w, h) is the size of the partial bitmap, (bw, bh) that of the source bitmap, and (xo, yo) is the offset in pixels into the source bitmap. putboxmask( int x, int y, int w, int h, void *dp ) As putbox, but do not write bitmap pixels of color zero. copybox( int x1, int y1, int w, int h, int x2, int y2 ) Copy the rectangular area at (x1, y1) of size (w, h), to (x2, y2) (bitblit). copyboxtocontext( int x1, int y1, int w, int h, GraphicsContext *gc, int x2, int y2 ) Copy the rectangular area at (x1, y1) of size (w, h), to position (x2, y2) in the context gc. copyboxfromtocontext( GraphicsContext *gc, int x1, int y1, int w, int h, int x2, int y2 ) Copy the rectangular area at (x1, y1) in the context gc, of size (w, h), to position (x2, y2) in the current context. This is more efficient than copyboxtocontext. - compiled bitmaps (linear 256 color mode only) compileboxmask( int w, int h, void *sdp, void *ddp ) Convert rectangular masked bitmap of size (w, h) at sdp to a compressed format that allows faster drawing, which is stored at ddp. Allocating w * h bytes for the compiled version is usually enough; an upper limit should be (w + 2) * h. int compiledboxmasksize( int w, int h, void *sdp ) Returns the size of the compiled version of the masked bitmap of size (w, h) at sdp that will be generated by compileboxmask. putboxmaskcompiled( int x, int y, int w, int h, void *dp ) Write compiled bitmap to screen. This is significantly faster than non-compiled masked bitmaps, especially for sparse bitmaps. - clipping enableclipping() Enable automatic clipping in most functions. disableclipping() Disable clipping. setclippingwindow( int x1, int y1, int x2, int y2 ) Set the clipping window to the rectangle with top-left corner (x1, y1) and bottom-right corner (x2, y2) (incl.). - graphics contexts and virtual screens setcontextvga( int mode ) Set the graphics context to the physical screen of a vga mode (as defined in svgalib). The mode must be set first. The only thing you can do with a planar (mode X-like) 256 color mode is aligned putbox, and use it as a target for copyscreen. setcontextvgavirtual( int mode ) Allocate a virtual screen in system memory identical to the graphics mode, and make that the current graphics context. setcontextvirtual( int w, int h, int bpp, int bitspp, void *vbuf ) Define the current graphics context to have a width of w pixels, height h, bpp bytes per pixel, bitspp significant color bits per pixel (8, 15, 16 or 24), with the framebuffer at vbuf. A 4 bytes per pixel context, with 24 significant color bits is also valid. getcontext( GraphicsContext *gc ) Save the current context in a structure variable. setcontext( GraphicsContext *gc ) Restore a previously saved context (make it the current context). freecontext( GraphicsContext *gc ) Free the space allocated for the virtual screen in the given context. copyscreen( GraphicsContext *gc ) Copy the current graphics context contents (screen data) to the specified graphics context (the physical screen, for example). Contexts are assumed to be identical in size. setscreenoffset( int o ) Set the offset in pixels into video memory for copyscreen and copyboxtoscreen, allows for page-flipping. Must be a multiple of the scanline width in bytes. It is reset to zero after completion of copyscreen. int enablepageflipping( GraphicsContext *gc ) Enable page flipping or triple buffering in copyscreen if the physical context gc can do it. Returns 3 if triple buffering will be used, 2 for page flipping, 0 if page flipping is not possible (due to video memory/mode limitations). When pageflipping is enabled, the screenoffset is ignored in copyscreen. - text writing, font handling setfont( int fw, int fh, void *fp ) Use the font stored as character bitmaps at fp, with characters of size (fw, fh), as the basic font for write operations. Note that the font included in the library must be expanded first, because it is stored bit-per-pixel; this is not required if the FONT_COMPRESSED writemode flag is set. setwritemode( int m ) Sets writemode flags. If WRITEMODE_MASKED is set (as opposed to WRITEMODE_OVERWRITE), only foreground pixels of the font are used for write operations; the screen background is not erased. If FONT_COMPRESSED is set (as opposed to FONT_EXPANDED), text writes will use the compressed bit-per-pixel font rather than the expanded font. write( int x, int y, char *s ) Write string s at (x, y) using currently selected font. writen( int x, int y, int n, char *s ) Write n character string s at (x, y). expandfont( int fw, int fh, int c, void *sfp, void *dfp ) Convert bit-per-pixel font at sfp, with characters of size (fw, fh), to an expanded font of character bitmaps, stored at dfp (size will be 256 * fw * fw * BYTESPERPIXEL). All non-zero pixels are set to color c. colorfont( int fw, int fh, int c, void *fp ) Set all nonzero pixels in the expanded font to color c. setfontcolors( int bg, int fg ) Set the background and foreground colors for the compressed font write mode. - VGA 256-color palette handling These functions are only valid in 256-color modes. getpalettecolor( int c, int *r, int *g, int *b ) Get red, green and blue values (in the range 0-63) of color c from the color-lookup-table, and store them as integers in the memory locations pointed to by r, g and b. setpalettecolor( int c, int r, int g, int b ) Set RGB values (0-63) for color c. getpalettecolors( int s, int n, void *dp ) Get RGB values of n colors starting at s, which are stored as a table of groups of three bytes at dp. setpalettecolors( int s, int n, void *dp ) Set RGB values of n colors starting at color s. getpalette( void *p ) Equivalent to getpalettecolors(0, 256, p). setpalette( void *p ) Equivalent to setpalettecolors(0, 256, p). setrgbpalette() Set 256-color RGB palette (bits 0-2 blue, 3-5 green, 6-7 red). Use with setpixelrgb. - miscellaneous clearscreen( int c ) Fill the entire screen with color c. scalebox( int w1, int h1, void *sdp, int w2, int h2, void *ddp ) Scale the bitmap of size (w1, h1) at sdp to size (w2, h2) and store it at ddp, which must be a large enough buffer. The pixel size of the current graphics context is used. setdisplaystart(int x, int y) Set the physical display start address to the pixel at (x, y). Can be used for hardware scrolling, or for page flipping (e.g. setdisplaystart(0, HEIGHT) displays from the second page). Make sure the scanline width (BYTEWIDTH) in bytes of the current context corresponds with the physical screen. Macros defined in vgagl.h: WIDTH The width in pixels of the current graphics context. HEIGHT Height in pixels. BYTESPERPIXEL Number of bytes per pixel (1, 2, 3 or 4). BYTEWIDTH Width of a scanline in bytes. COLORS Number of colors. BITSPERPIXEL Number of significant color bits. VBUF Address of the framebuffer. __clip Clipping flag. __clipx1 Top-left corner of clipping window. __clipy1 __clipx2 Bottom-right corner of clipping window. __clipy2 Use the environment variable GSVGAMODE to select the graphics mode used by the testgl program (e.g. export GSVGAMODE=G640x480x256). It may be interesting to compare the framebuffer video speeds for certain modes, especially among Vesa Local Bus cards (even if only 320x200x256 works). There is considerable variation in performance among VLB motherboard implementations and cards. If you want, you can mail them to me (hhanemaa@cs.ruu.nl) and I'll collect the results at this place. Please state CPU, card type/chipset, and bus type (of the card)/(ISA) bus speed. The speedtest program is using aligned REP STOSL (memset), which is relatively slow on a 486 (4 cycles); unrolled MOV's may be faster. It does show that many VLB cards have in fact only a 16-bit bus interface (like my Cirrus 5426 based card). The maximum throughput using STOSL on a 386 (5 cycles) is about 15M/s at 16-bit VLB 40MHz, 30M/s with 32 bits. Anyone with an ET4000/W32(i) to show off? The 'fun' program displays a frame rate that is also very dependent on general memory architecture (it uses two virtual screens). Notice that the frame rate has a significant variation between runs (up to 15% on my machine), but it doesn't change within a run. I believe this is because of pages mapping to the same external cache slot, which happens quite often with a direct mapped cache (a bad thing for a multi-tasking VM OS). This means that if you were to run a small but memory-intensive program taking say a day to calculate something, it would be a good idea to display timed progress information at the start. Restarting until the speed is good would possibly save several hours of computation time. Note: there seem to be VLB motherboards around that have problems with (sound) DMA when writing video data to the local bus (possibly related to running the VLB in 'slave' mode). Speeds are in MByte/s. bus 256-color hicolor truec. card system speed 320x200 640x480 800x600 640x480 640x480 AVGA3, CL-GD5426, VLB 386DX/40 40.0 12.5 13.7 12.8 7.6 4.6 --same, high MCLK 386DX/40 40.0 15.5 15.5 15.5 11.7 8.4 --same 486SX/40 40.0 15.6 15.6 15.6 11.7 8.4 --same, low write delay 486SX/40 40.0 - 19.5 - - - Trident 9000, 512K ISA 386DX/40 8.0 2.1 2.2 2.2 - - Trident 8900C, ISA 386DX/33 2.6 3.1 2.1 - - Tseng MegaVGA/1024 ISA 486DX/33 13.3 8.5 8.5 8.5 8.5 6.0 --ET4000, AT&T491/2 DAC 386SX/40 10.0 4.8 4.8 4.8 4.8 4.8 Trident 9000, 512K ISA 486DX/33 13.3 2.9 2.3 2.5 - - S3-805 VLB (stosl) 486DX2/66 33 10.8 - - - - --same (stosw) 486DX2/66 33 16.0 - - - - ATI Ultra Pro EISA 486DX/50 8 6.2 6.2 6.2 6.2 6.2 Morse KP1024 ET4000 486SX/40 10.0 3.8 3.8 3.8 --same 486SX/40 13.3 5.2 5.2 5.2 Oak OTI-087 486DX2/66 33 7.7 6.6 6.7 CL-GD5428 (same mb) 486DX2/66 33 8.0 6.8 6.8 CL-GD5434E VLB 0-wait 486SX/33 33 56.1 56.1 54.2 52.5 48.5 --same, non 0-wait 486SX/33 33 30.2 29.1 28.1 25.4 Note For three bytes per pixel (true color) modes, it is possible that pixels cross a SVGA segment boundary. This should be correctly handled by most functions. It can be avoided by using a logical scanline length that is a divisor of 65536 (a power of 2), like 1024 (as opposed to 960) for 320x200 and 2048 (1920) for 640x480. For 800x600, this is impractical (4096 as opposed to 2400 doesn't fit in 2MB). Alternatively, avoid those functions by using a virtual screen. Question: How do I poll the keyboard without waiting and handle multiple keypresses? You can have complete keyboard control by using RAW mode. An example should be in the kbd-08? package (nic.funet.fi, /pub/Linux/PEOPLE/Linus or similar). There is now a low-level keyboard interface in svgalib. There is also a seperate 'rawkey' library for use with svgalib, by Russell Marks. Q: What's the fuss about a DLL library? A: The building of a DLL library includes a conversion, at the assembler level, of all references in the library code of exported global variables into indirect references with some overhead added to preserve register values. This is not very efficient if the global variables are used all over the place (e.g. currentcontext and its fields). The testgl program ran 20% slower because of this. Therefore, the library internally uses a copy of currentcontext that is not exported. This means that the current context may only be changed with vgagl functions.