Skip to content

display_driver: a direct panel reports each frame once, and presents counts it - #24

Closed
bdbarnett wants to merge 1 commit into
mainfrom
displaydev-fps
Closed

bdbarnett wants to merge 1 commit into
mainfrom
displaydev-fps

Conversation

@bdbarnett

@bdbarnett bdbarnett commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

On a direct-framebuffer panel, display_driver now reports each frame once, whichever way the frame was presented. presents counts it either way.

_flush_cb_direct hands every dirty area to the panel's flush_rect. On a frame's last area it used to call show() and count a present only when flush_rect could not sync the area. A panel whose flush_rect does sync, like the P4's DSI panel through mipidsi's refresh_rect, never counted a present, so presents stayed at 0 there. Now the last area ends in show() when flush_rect didn't sync, or in the panel's frame_done() when it did, and presents += 1 in both cases.

frame_done() is the hook added to displaydev's DisplayDriver for its new frame-rate meter (PyDevices/pydevices#129). It does nothing unless measure_fps is on. A displaydev without it is fine too: the call is skipped by getattr.

I made the change here and not only in lvgl-micropython's vendored copy, which is where the brief put it. This is the canonical copy, so a sync would have overwritten an edit made only there, and lvgl-python, which gives CPython its display_driver and runs CastDisplay, would never have got it. The lvgl-micropython PR carries the identical file.

Measured (desktop, real LVGL, FBDisplay in DIRECT mode, two labels redrawn every 40 ms)

runtime panel frames (displaydev) presents flushes
CPython buffer with refresh_rect (P4's branch) 124 124 249
CPython plain buffer (CastDisplay's branch) 124 124 249
MicroPython unix buffer with refresh_rect 125 125 251
MicroPython unix plain buffer 124 124 249
CPython CastDisplay running lv_test_timer 166 166 174

With the old display_driver, the refresh_rect panel reads frames 0 and presents 0 against 249 flushes.

tests/test_display_driver_direct_frames.py runs the real _flush_cb_direct against stand-in panels. Against the old code it fails the synced and no-frame_done cases.

After this merges, lvgl-micropython and lvgl-python need their usual sync.

…counts it

On a DIRECT panel the last area of a frame now always ends in one present:
show() when flush_rect could not sync the area, otherwise the panel's
frame_done() (displaydev's frame-rate hook, a no-op unless measure_fps is
on). presents counts both, so it is a frame count on every direct panel;
before, a panel whose flush_rect synced (the P4's DSI panel) never counted
one.
@bdbarnett

Copy link
Copy Markdown
Contributor Author

Closing in favour of the move: display_driver now lives in PyDevices/pydevices lib/, and the file that lands there is this PR's version, frame hook and all (PyDevices/pydevices#129). The tests here moved with it, to pydevices' tests/test_lvgl_display_driver.py. Removal from this repo is #25.

@bdbarnett bdbarnett closed this Oct 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant