Writing a Glide 2 replacement for an early Glide game
What to know
A game that draws everything through Glide can be drawn at any resolution by replacing the library: the game passes screen coordinates, colours and texture memory, and nothing else depends on the Voodoo's 640 × 480. POD's 3dfx build runs unchanged through GameFrame's wrappers/glide (Rust, built for 32-bit Windows, OpenGL). What mattered, each observed or measured there:
- The file and the names. Early Glide 2 games import
glide.dll, notglide2x.dll, by decorated__stdcallnames (_grGlideInit@0,_grSstOpen@24). Export exactly those: list them withpeinfo --importsandstrings, and write them into the.deffile. - No window. The early
grSstOpen(res, refresh, format, origin, smoothing, buffers)takes no window handle: a Voodoo drew full screen. Find the game's own window (by class, even while hidden: POD calls Glide before it shows the window) and draw into it. - List the calls with their arguments first. A capstone scan of every call site, reading the constants pushed before it, gives the game's whole use of the card in one table (POD: 47 calls, 360 sites): which combiner settings, blend factors, depth mode, fog, texture formats and LFB modes need to be right, and which never occur.
- More than one thread. Games call Glide from a loading thread too. An OpenGL context belongs to one thread: record every call as a command and replay on one render thread, answering only queries (
grSstScreenWidth,grTexCalcMemRequired,grLfbGetReadPtr) at once. - The LFB. The write pointer has a fixed stride of 1024 pixels (2048 bytes at 16 bits, 4096 at 32), and a game may set the write mode after taking the pointer. Hand out a buffer filled with a marker and read what changed at
grLfbEnd. Reads of the depth buffer exist (POD's lens flare tests for0xffff): copy the depth down to the game's resolution. - Depth. Map the W buffer to
1 - oowand the Z buffer toooz / 65535, so Glide's compare functions are OpenGL's as they are; turn on depth clamping. - Texture coordinates.
sow/towrun 0–256 across the longer side, divided by w; passs·was a perspective-correct varying and the coloursnoperspective, as Glide does. - Gamma belongs in the final copy to the window (the Voodoo's output table), not in the blending.
- Software OpenGL under an emulator is slow. Mesa's llvmpipe in a QEMU-emulated PC drew the menus at 2–5 frames a second;
LP_NATIVE_VECTOR_WIDTH=128roughly doubled it. Log frames per second and where the time goes from the start.