diff --git a/docs/port/BLOCKED.md b/docs/port/BLOCKED.md index 7a970dab..28760f9f 100644 --- a/docs/port/BLOCKED.md +++ b/docs/port/BLOCKED.md @@ -123,8 +123,16 @@ hitches**, which draws the splash's 45-unit build-in at **12โ€“17 distinct alpha instead of 45** and the companion glow's 15-unit rise at **four to six instead of fifteen**. -โš ๏ธ That is `llvmpipe` under Xvfb and **not a measurement of the human's -hardware**, so it is a candidate and not a cause. The point is that the line +๐Ÿ”ด **DOWNGRADED the next iteration by a matched control, and the downgrade is +mine.** An empty scene in the same container runs at **161.6 fps**, and matched +textured controls give **23.9 fps for three full-screen quads and 11.2 for +seven** โ€” every port screen lands inside that bracket in the order its quad count +predicts (`main_menu`'s 9.7 against `tex7`'s 11.2). So the rate is software +rasterisation of large textured alpha quads and **the port's draw path has no +case to answer**; on any GPU the fade gets its full 45 steps. Unless the human +ran it software-rendered this is not what they saw, which means **every candidate +for finding 4 is now dead or near-dead**. Recorded as a dead end rather than left +standing as a lead. The point is that the line now prints on every boot, so **the next play-test answers it for free**. See [`port-frame-rate.md`](port-frame-rate.md). diff --git a/docs/port/port-frame-rate.md b/docs/port/port-frame-rate.md index 678771ea..0655796b 100644 --- a/docs/port/port-frame-rate.md +++ b/docs/port/port-frame-rate.md @@ -1,8 +1,8 @@ # The port never reported its own frame rate โ€” it does now, and it is 13โ€“25 fps here -**Status:** โœ… **instrument added and measured.** ๐ŸŸก **The consequence is a live -candidate for play-test finding 4 and it is environment-dependent, so it is -recorded as a candidate and not as a cause.** Written 2026-09-01 by the Port at +**Status:** โœ… **instrument added and measured.** ๐Ÿ”ด **The candidate it raised for +play-test finding 4 is now DOWNGRADED to probably-dead by a matched control โ€” +see the last section. The port's draw path has no case to answer.** Written 2026-09-01 by the Port at `977965e`; HANDOFF on this branch answers `9ca1eb5`. ## The gap this closes @@ -132,3 +132,93 @@ finding over. and not decoded per frame โ€” that was checked and is not the cause. * That capping or vsyncing would help. It would not raise the rate here, and changing presentation behaviour on my own authority is not mine to do. + + +--- + +# The control: it is the software rasteriser, and the port has no case to answer + +Written the iteration after the section above, because *"is 9.7 fps llvmpipe or +something in our draw path"* was left open and it is not a question to leave open +after publishing a candidate cause. + +## Pre-registered (R2) + +> If the rasteriser is the limit, a near-empty Godot scene in this same container +> will also run at roughly 10โ€“25 fps. If my draw path is the limit, it will run +> far faster โ€” take **>100 fps** as the discriminator. + +Same container, same Xvfb, same 1280ร—720 viewport, same `[rendering]` settings, +almost nothing drawn: + +``` +FPSPROBE mode=empty: 651 frames in 4.03 s -- 161.6 fps, worst gap 54 ms +``` + +**161.6 fps.** The engine loop, the viewport and the present path are not the +limit, by a factor of sixteen over the menu. + +## ๐Ÿ”ด And the first control was not a control + +Its `fill` modes drew **untextured** `draw_rect`s while every element the port +draws is a **texture**. A control that does not do what its subject does bounds +nothing โ€” and it showed: the port's splashes were achieving ~21 Mpx/s against +that control's ~50, which read as the port being mysteriously slow and was really +the control being mysteriously fast. Adding a matched textured mode: + +| mode | full-screen quads | achieved | +|---|---|---| +| `empty` | 0 | **161.6 fps** | +| `fill3` | 3, untextured | 31.5 | +| **`tex3`** | **3, textured** | **23.9** | +| `fill7` | 7, untextured | 12.7 | +| **`tex7`** | **7, textured** | **11.2** | + +## The port sits inside the bracket, ordered by large-quad count + +| screen | full-screen-ish quads | measured | bracket | +|---|---|---|---| +| `publisher_logo` | 1 | 17.3โ€“25.0 | โ‰ˆ `tex3` | +| `developer_logos` | 1 | 16.7โ€“22.8 | โ‰ˆ `tex3` | +| `title` | 6 | 12.7โ€“17.2 | between `tex3` and `tex7` | +| **`main_menu`** | **5** | **9.7** | โ‰ˆ `tex7` (11.2) | + +**Every screen lands between the two matched controls, in the order the quad +count predicts.** The port is drawing large textured alpha quads on a software +rasteriser at exactly the rate a software rasteriser draws large textured alpha +quads. + +โš ๏ธ Note the control's own spread: `fill3` measured **18.0** on one run and +**31.5** on another. The container's load swings by ~1.75ร—, so the absolute +numbers here are noise-dominated and only the **ordering and the bracket** are +load-invariant โ€” which is what `TEMPORAL-VERIFICATION.md` ยง3 says to prefer, and +the reason this conclusion rests on those rather than on any single figure. + +## ๐Ÿ”ด So the finding-4 candidate is downgraded, and I am saying so plainly + +The section above called the frame rate *"the first candidate for finding 4 that +is not already dead"*. **That now looks wrong, and it was mine.** + +The quantisation argument still holds โ€” a fade drawn in four steps is not a fade +drawn in fifteen โ€” but it only bites at these frame rates, and these frame rates +are a property of **software rasterisation in this container**. Five to seven +full-screen quads at 720p is nothing to any GPU; on real hardware the port would +hit vsync and the fade would get its full 45 steps. + +So unless the human ran the port software-rendered, this is not what they saw, +and **every candidate for play-test finding 4 is now dead or near-dead.** That is +an honest dead end rather than a lead, and it is written as one: leaving a +plausible-sounding cause standing when its own control has undercut it is exactly +how *"close but not right"* got explained four different wrong ways. + +**The one thing that would revive it costs the human nothing**: the rate line now +prints on every boot. If their next run says 60 fps, this is finished. + +## What the port does NOT need + +* No draw-path optimisation. 161.6 fps empty says the loop is fine, and the + screens sit on the fill curve exactly where their quad counts put them. +* No texture caching work โ€” already done at `load_screen`, checked last + iteration. +* No `max_fps` or vsync change. It would not raise the rate here, and it is a + presentation decision rather than a defect.