The cockpit displays were updating every two to three seconds while the
3D view held a perfectly smooth 55 fps. This is why, and it is one line.
Every device was created D3DCREATE_SOFTWARE_VERTEXPROCESSING - every
vertex on the track transformed and lit on the CPU, on the one core this
game uses for everything. That was not a choice when the engine was
written; there was no hardware to hand it to. The error message beneath
the call still says "Couldn't create HARDWARE_VERTEXPROCESSING device",
so the flag was changed at some point and the message left behind.
Measured on the biggest track, 1920x1080:
software foreground 17.2 ms background 1.2 ms 2.4 gauge passes/s
hardware foreground 0.2 ms background 17.9 ms 50.0 gauge passes/s
The frame loop runs the foreground and then spends whatever is LEFT on
the background gauge work. A foreground costing 17.2 ms of an 18 ms frame
leaves nothing, so the gauge loop got the single pass it is guaranteed
and no more. A pass needs about twenty steps - eighteen gauges and three
display copies - so the cockpit ran at two passes a second, and since the
renderer walks a sixteen-step rate wheel, a gauge on one step redrew once
per SIXTEEN of those. Three seconds. The map, the clock, the boost gauge
and the sim still running after the fade to black were all that one
number.
Hardware T&L is now the default and sw is the way back. Fixed-function
lighting and fog are not bit-identical between the old software path and
a driver, so the escape hatch stays - but the picture was checked against
both and the difference is not the one worth defending. A cockpit whose
instruments update twice a second is. It falls back to software by itself
if the adapter has no hardware T&L.
The instruments that found it stay in, because nothing about this was
visible from outside:
- FrameSplit, under RP412GAUGEDIAG, reports foreground against background
against whole frame. APPMGR has computed those four timestamps every
frame since forever and never reported one of them; it would have
pointed here on the first day.
- FrameDiag reports frames per second on the same window, so the gauge
sweep rate can be read against the frame rate rather than guessed at.
- ProfileReport, which already existed and was only reachable through F11
on the RIO controls mapper - not the mapper a desktop player runs, so
in practice unreachable - now runs on a timer under RP412GAUGEPROFILE.
Its per-gauge line gains the rate mask and tier, which is what names a
display as one-in-sixteen rather than merely slow.
- The winners' circle logs what its exterior and name-plate rebuilds
cost, since nothing else runs while they do.
RP412VSYNC is here too, and it is honest about itself: presenting
IMMEDIATE was measured and made no difference to the frame budget,
because the frame was full of work rather than waiting. It stays as a
latency-against-tearing preference, not a fix.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two testers reported the map and the countdown clock freezing, one of
them only on larger, more complex maps, and one of them until a death.
Both details point at the same place.
The gauges and the cockpit displays are redrawn in whatever time is left
after the 3D view. The background loop is guaranteed a single pass per
frame and gets more only while time remains before the frame is due, and
one pass drew exactly one gauge. So a full sweep of ninety-odd gauges
needed ninety-odd passes - free when there is spare frame, but on a busy
map the 3D view eats all of it, the loop drops to its one guaranteed
pass, and a sweep takes ninety-odd FRAMES. Seconds. A death makes the
renderer skip every static object, the budget frees up, and the backlog
drains at once: the display appears to come back to life.
Worse, the copy phase that follows ended after a SINGLE display, so the
map - one of three - came round only every third sweep.
So: draw gauges to a 2ms slice rather than one per pass, which ties the
refresh rate to elapsed time instead of to how much spare frame there
happened to be; and copy every display before reporting the sweep done.
Measured on a deliberately starved frame budget, which reproduces the
reported symptom: 0.7 sweeps/s before, 3.1 after. At a normal budget
20/s, against 18-19 before - no cost to the healthy case. RP412GAUGESLICE
tunes the slice and 0 restores the old behaviour, which reproduces the
0.7 exactly. RP412GAUGEDIAG=1 logs the rate; watching the screen cannot
tell a display that has stopped refreshing from one whose picture simply
is not changing, which is what made this hard to see.
Also fixes the constructor calling Update() three lines before it
initialised mDisplayToUpdate, so the first pass indexed the D3D device
and surface arrays with whatever was on the stack.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Imports the current Win32 source for the pod-racing game 'Red Planet',
built on the MUNGA engine and its L4 (Win32/DirectX) platform layer:
- MUNGA / MUNGA_L4: cross-platform engine core and Win32 backend
- RP / RP_L4: Red Planet game logic and Win32 application
- DivLoader, Setup1: asset loader and installer project
- lib, MUNGA_L4/openal, MUNGA_L4/sos: third-party audio dependencies
Removed stale Subversion metadata and added .gitignore/.gitattributes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>