Skip to content

runtime: Android buffer-stuffing recovery (makepad #128) until the next sweep - #546

Open
ymote wants to merge 5 commits into
mainfrom
fix/android-buffer-stuffing
Open

ymote wants to merge 5 commits into
mainfrom
fix/android-buffer-stuffing

Conversation

@ymote

@ymote ymote commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Why

A performance soak of the phone's All apps list on a OnePlus 6 (Android 15, 60 Hz) found that scrolling feels slow because of lag, not frame rate. The soak ran main 8b98596 as a test package for 60 minutes: 960 scripted drags, flings and flicks with 8 ms touch injection, measured against SurfaceFlinger present times and phone.frames.

  • Frame rate: a median of 60 fps, with flat memory and no crashes.

  • Lag: within a drag, the delay from finger to screen is constant, but it falls into one of three groups:

    Finger-to-screen delay Share of drags
    ~37 ms 53%
    ~53 ms (one extra frame) 40%
    ~70 ms (two extra frames) 8%

    The first drag after opening All apps is always in the slow groups.

  • Cause: buffer stuffing in Makepad's Android frame loop. A frame takes about 12 ms from the vsync beat to the queue, against a latch at about 16 ms. One slow frame, usually the first after idle, misses the latch, and every later frame waits one refresh in the queue until the app goes idle. Instrumented runs found 55 such events and no recoveries.

What

This stacks OctoSense-org/makepad#128 on the pinned Makepad (d653bc44) as tools/runtime-patches/makepad-android-buffer-stuffing.patch, and updates runtime-patches.lock.json with the stacked entry, its sha256, the tree and a product_fixes line.

  • On API 33+, the Choreographer beat carries the frame's expected presentation time from VsyncCallback FrameData.
  • EGL frame timestamps report each frame's display time.
  • When two frames in a row reach the screen at least half a refresh after their expected time while a finger is down, one beat is left unpainted so the extra queued frame drains.
  • setprop debug.makepad.stuffing off disables it.

The next Makepad sweep drops this patch once #128 is merged upstream into our fork's main.

Device results

OnePlus 6, a Home test package built from this branch (dev.makepad.octosense.scrollfinal, 0833dfe). Production Home was not replaced. All apps, recovery off or on through the property, two interleaved rounds of 5 minutes each:

Off On
Drags at ~37 / ~53 / ~70 ms 38% / 46% / 16% 82% / 18% / 0%
Median drag delay 53.4 ms 37.0 ms
Dropped frames per gesture 0.89 1.10
Skips — 56

The extra dropped frames are the stuffed queue's lost cushion. A slow frame now shows as one repeated frame, mostly at the start of a drag and in its coast; fling coasts are unchanged. The follow-up that removes both is cheaper frames: GL encode is 5 ms of the 12.

The table above is from 0833dfe. 152001a then armed the detector only while a finger is down. 4c04edf stacks #128's second commit. A refresh without a new frame drains the queue, so frames painted before one never arm a skip. Re-checked with a test package built from 4c04edf (dev.makepad.octosense.scrollfinal2):

  • Touching again right after a fling (the finger lands about 0.2 s after the fling stops). 0833dfe and 4c04edf ran interleaved, 2 × 4 minutes each. Skips armed by the fling's own frames fell from 10 of 76 touches to 0 of 81. Missed refreshes in the first 300 ms after the touch fell from 0.18 per touch to 0.
  • Same session, off and on. Drags with an extra queued frame went from 3 of 46 to 0 of 45, and dropped frames per gesture from 0.59 to 0.56. The phone stuffed far less often than in the run above.
  • Input timing. In every run, on or off, 8 to 13 of 45 drags lag a frame before the draw: the touch reaches the draw a frame late. That is input timing, which this patch doesn't touch.

Checks

🤖 Generated with Claude Code

…xt sweep

Stacks OctoSense-org/makepad#128 on the pinned makepad (d653bc44):

- The Choreographer beat carries its expected presentation time (API 33+).
- EGL frame timestamps report each frame's display time.
- When two frames in a row reach the screen half a refresh late while a
  finger is down, one beat is left unpainted so the extra queued frame
  drains.

In the phone's All apps list, a drag stops trailing the finger by a frame
or two after one slow frame: drags at the shortest delay rose from 52% to
84% on a OnePlus 6.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…kepad #128)

Restacks makepad-android-buffer-stuffing.patch on makepad #128's second
commit: a refresh without a new frame (an unpainted beat, or an idle app's
stopped beats) drains the queue, so frames painted before one never arm a
skip. Without it, a stuffed coast's last frames, read back at the next
gesture's first swap, could drop that gesture's second beat.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#548 stacked makepad-apple-ui-font.patch on the same lock lines. The
buffer-stuffing patch now follows it (stacked entry and product fix after
#548's) and applies unchanged; the lock tree is regenerated from the whole
stack: 9d9aef6e, which differs from main's 90b364c1 only in this patch's
Android files. `tools/setup.py --check --cargo` passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ymote and others added 2 commits October 22, 2026 01:34
Main's lock now stacks makepad-map-texture-depth.patch as the 38th patch
(#435). The Android buffer-stuffing patch follows it as the 39th, unchanged
(sha 7f87b527); it touches no file the map patch does. The makepad tree,
replayed over the whole stack with git apply --index, is fcd2a327.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#554 stacked makepad-finance-seed.patch as the 39th patch. The Android
buffer-stuffing patch follows it as the 40th, unchanged (sha 7f87b527); the
two touch disjoint files. The makepad tree, replayed over the whole stack
with git apply --index, is a9c02164. `tools/setup.py --check --cargo` passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant