Repository navigation
Conversation
… the panel's frame buffers The DPI panel was always created with one frame buffer, private to the BSP, so LVGL had to render into separate PSRAM draw buffers and every flush copied the area into the frame buffer the panel scans out. - Kconfig M5STACK_TAB5_DPI_NUM_FBS (1..3, default 1) sets num_fbs for all three panel variants (ILI9881, ST7123, ST7121). - frame_buffers() returns the panel's frame buffers (cached by initialize_lcd()), frame_buffer_size() their size, so an application can render straight into them; esp_lcd_panel_draw_bitmap() on a frame buffer switches the panel to it instead of copying. - initialize_display(const DisplayConfig &): with render_to_frame_buffers the BSP sets LVGL up in DIRECT mode on two of the frame buffers and its flush switches buffers once the frame's last area is rendered. No draw buffers and no rotation scratch buffer are allocated. initialize_display(size_t) is unchanged. - The example gains an opt-in menuconfig option for that mode; README and example README document it, with the render time measured on a Tab5 (full screen 75.6 -> 48.6 ms) and the PSRAM it saves. Defaults are unchanged: one frame buffer, draw buffers, copying flush. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…_flush_ready() itself The DPI transfer-done interrupt (notify_lvgl_flush_ready) only gives draw_done_sem_ now; the BSP's own flush() calls lv_display_flush_ready(). An application that installs its own flush callback on the frame buffers (frame_buffers(), DisplayConfig::render_to_frame_buffers) and relies on the interrupt to finish the flush hangs on its first frame. Say so in both doc comments. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…, or use a flush wait callback Make the custom-flush-callback note precise: LVGL waits for lv_display_flush_ready() after every flush-callback call (per area), and lv_display_set_flush_wait_cb() is the alternative that needs no call. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
@finger563 could you take a look when you have a moment? This adds multiple DPI frame buffers to the Tab5 BSP and is stacked on #738 (details in my comment there: #738 (comment)). It's a draft until #738 lands; the default config behaves exactly as #738 alone. Thanks! |
…uffer swaps With two DPI frame buffers, esp_lcd_panel_draw_bitmap() on a frame buffer only queues the switch (cache write-back, cur_fb_index); the DMA takes the new buffer up when it restarts at the end of the frame it is sending. A renderer that starts on the previous buffer at once draws into the buffer the panel is still scanning out, and the frame tears. on_color_trans_done cannot tell when the switch lands: for a frame buffer the driver calls it synchronously, before the switch. - present_frame(frame_buffer, timeout_ms = 100): queues the switch, then waits for the DMA's frame-done event (on_frame_buf_complete; on_refresh_done before ESP-IDF v5.5.5 / v6.0.3, selected at compile time), after which the previous buffer is free. Events from before the switch was queued are dropped first. A timeout logs once and returns false instead of stalling. - set_vsync_enabled() / vsync_enabled() turn the wait off and on. - The frame-done callback and its semaphore are registered only with CONFIG_M5STACK_TAB5_DPI_NUM_FBS >= 2, so the default build is unchanged. - DisplayConfig::render_to_frame_buffers now shows each frame with present_frame(), so the BSP's DIRECT mode does not tear. README updated. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ing into the frame buffers The flush already waits for the panel's frame-done event, so the example's fixed 16 ms sleep after every pass would halve the frame rate. The default configuration keeps the fixed sleep. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Hardware results on a Tab5 (ST71xx panel, ESP-IDF v6.1)Measured with a small display benchmark added locally to the
DSI underruns were counted from the driver's "underrun happens" log lines. These are single runs. Branches tested: espp
Takeaways:
Build note: neither PR builds as-is on ESP-IDF v6.1. v6.1 added 🤖 Generated with Claude Code |
Why is this PR needed: with one frame buffer, every Tab5 redraw is copied into the image the panel is sending, so the UI tears. The current code can't fix this:
num_fbs = 1;Displayonly renders in PARTIAL mode, copying from its own draw buffers.Description
Optional tear-free LVGL rendering on the Tab5, for the cost of one extra frame buffer. Off by
default: the default build behaves exactly as before.
Stacked on #738.
CONFIG_M5STACK_TAB5_DPI_NUM_FBS(1-3, default 1).initialize_display({.render_to_frame_buffers = true})(defaultfalse): LVGL draws into theframe buffer that is not on screen. The flush switches the panel to it, then waits for the panel's
frame-done event before LVGL draws again.
frame_buffers()for applications with their own renderer.Motivation and Context
Measured with the
m5stack-tab5example on a Tab5 (ST7123, ESP-IDF v6.0.0), BSP default drawbuffers, with the same LVGL loop in both builds:
mainlonger needed. Net: 1.2 MB.
refresh. Heavy animations therefore run at half the panel rate (29 FPS) instead of tearing.
How has this been tested?
clang-format clean.
as the base.
Types of changes
🤖 Generated with Claude Code