Skip to content

Writing a PowerVR SGL replacement for a PCX1/PCX2 game ​

What to know ​

PowerVR's first chips (PCX1, PCX2) were driven through VideoLogic's SGL. Unlike Glide, SGL is a retained scene graph: the game builds display lists of transforms, materials, meshes, lights and cameras, edits a few transforms each frame and calls sgl_render. A stand-in keeps the graph and draws it with any API at any size. POD's PowerVR build runs through GameFrame's wrappers/sgl (Rust, 32-bit Windows, OpenGL). What mattered, each observed or measured there:

  • Look for the SDK on the game's disc. Games shipped the PowerVR driver package, with sgl.h and sglwin32.h in it (POD: POWERVR/310C3.ZIP). The headers give every signature (all __cdecl, undecorated names) and the error codes; nothing needs fetching.
  • sglhw.ini. The driver's installer writes it into the Windows folder. A game may read values from it and divide by them (POD reads the region size, 0 without the file, and divides). The stand-in writes the installer's values when the file is missing.
  • The address callback. With sgl_use_address_mode the game names a function SGL calls for the memory to render each frame into. The game's callback also finishes the frame before it: draws its 2D overlay (the dashboard), shows it, and locks the next back buffer. Call it at the first sgl_render of a frame, fill the viewport in that memory with a marker, draw the scene with OpenGL, and put every non-marker pixel of the picture the game then shows on top. That needs the picture: a small hook in the DirectDraw stand-in passes it on. The callback's parameter block is packed (pointer, 16-bit stride, 8-bit depth).
  • Materials inside meshes. Material calls made right after sgl_create_mesh belong to the mesh's faces; made elsewhere they are entries of the current list. Lists made with preserve_state give the transform, material and lights back when they end.
  • Names. Calls with generate_name false return 0 (sgl_no_err), not a name.
  • The immediate mode. SGL's other half (sgltri_*) takes faces already projected to the screen, in Direct3D's D3DTLVERTEX layout (SGLVERTEX), under an SGLCONTEXT of 0x90 bytes. Hardwar (1998) uses it. Draw the faces through the same pipeline. A vertex at screen (x, y) with 1/w becomes the camera-space point (x w, -y w, w) under a camera that maps it straight back, with the nearest w as the near plane. PowerVR's own SGLMID4.dll answers what the header leaves open. A face clockwise on the screen faces the camera. Faces of less than 1/32 pixel are dropped. Flat shading takes the first vertex's colour. The fog density (0 to 31) is a power-of-two register on a depth of 0.01 / w. Translucency is one 4-bit level per face. The driver sorts translucent passes, one per call and facing, farthest first; it never sorts single faces. It never reads SGLTT_VERTEXFOG.
  • A test without the game. A small Windows program that makes the same calls on a known scene (a textured cube under a 2D bar) checks the projection, lighting, textures and the overlay where the game itself cannot run (wrappers/sgl/test/sgltest.c, and sgltritest.c for the immediate mode).

Still guesses ​

The projection from the camera rectangle, the fog formula, the default material and how a light volume adds light are inferred from the headers' names and the game's arguments; each is marked Deviation: in the stand-in until a picture of the original settles it.

Code: Apache 2.0. Content: CC0 1.0. No game material: bring your own copy.