mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-10-04 14:25:08 +00:00
Scrolling ran at 44-46 fps on a 2x128x64 chain and 14-17% of frames took 41-53ms, which reads as judder. Four independent causes, each measured on the hardware; details and the diagnostic recipe are in docs/SCROLL_PERFORMANCE.md. The high-FPS loop slept a flat 8ms after every render. display() has already blocked on the panel's vsync by then, so that sleep was added to a wait that had happened: ~4ms of render plus 8ms put each iteration at ~12ms against a 10ms refresh grid, so every swap missed a refresh and the loop settled at 50fps while asking for 125 -- with no headroom, so a further 14% of frames slipped again. It now sleeps only the remainder, with a 1ms floor so plugin threads still get the GIL. ScrollHelper stepped position on a wall clock at 1/scroll_delay steps per second. Plugins set scroll_delay to the frame period, so that comparison sat exactly on its own threshold: a frame arriving a hair early moved zero pixels and rendered an identical frame, dirty-tracking skipped the swap, it returned in ~2ms, and the beat repeated. No scroll_delay value tunes that out -- a shorter delay trades stalled frames for periodic double-steps. Both modes now accumulate elapsed time at the same configured speed, so position stays proportional to real time. Sub-pixel blending goes back to off by default. It renders a half-step by mixing two adjacent columns, which on a coarse panel showing pixel-font text alternates crisp and smeared frames and reads as shimmer -- visibly worse than integer stepping on the hardware. Vegas mode still opts in. disk_cache uses orjson when importable, falling back to the stdlib. Encoding a ~1MB record drops from 14.8ms to 5.4ms end-to-end, and that work holds the GIL while a marquee is on screen. display_manager also checksummed the whole framebuffer twice per frame (dirty tracking, then the preview snapshot); the snapshot now takes the checksum the caller already computed. New src/common/scroll_config.py resolves scroll settings in one place. Five ticker plugins each hand-rolled this and disagreed: odds-ticker ranked the deprecated scroll_pixels_per_second above the documented scroll_speed/delay pair, and because that key carries a schema default the documented settings were dead for every user (ChuckBuilds/ledmatrix-plugins#408), while ledmatrix-leaderboard read the same key only as a fallback. The resolver also warns when a speed will not advance a whole number of pixels per refresh, which is the property that actually determines whether a scroll looks smooth. scripts/build_rgbmatrix_nogil.sh rebuilds the rgbmatrix binding so it releases the GIL. Upstream declares SwapOnVSync without nogil, unlike SetPixel/Clear/Fill beside it, so the render thread held the GIL for the whole vsync wait and starved background threads into long uninterruptible bursts. The script patches, builds and self-verifies into a scratch tree; --install backs up the original and rolls back if the service does not come back healthy. Measured after: 100 fps locked, no stalls observed, render thread down from 51% to 19% of one core. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
LEDMatrix Documentation
This directory contains guides, references, and architectural notes for the LEDMatrix project. If you are setting up a Pi for the first time, start with the project root README — it covers hardware, OS imaging, and the one-shot installer. The pages here go deeper.
I'm a new user
- GETTING_STARTED.md — first-time setup walkthrough
- WEB_INTERFACE_GUIDE.md — using the web UI
- PLUGIN_STORE_GUIDE.md — installing and managing plugins
- WIFI_NETWORK_SETUP.md — WiFi and AP-mode setup
- TROUBLESHOOTING.md — common issues and fixes
- SSH_UNAVAILABLE_AFTER_INSTALL.md — recovering SSH after install
- CONFIG_DEBUGGING.md — diagnosing config problems
- LOW_MEMORY_BOARDS.md — Pi Zero 2 W / 3B+ / 1GB Pi 4 memory limits
I want to write a plugin
Start here:
- PLUGIN_DEVELOPMENT_GUIDE.md — end-to-end workflow
- PLUGIN_QUICK_REFERENCE.md — cheat sheet
- PLUGIN_API_REFERENCE.md — display, cache, and plugin-manager APIs
- PLUGIN_ERROR_HANDLING.md — error-handling patterns
- DEV_PREVIEW.md — preview plugins on your dev machine without a Pi
- EMULATOR_SETUP_GUIDE.md — running the matrix emulator
Going deeper:
- ADVANCED_PLUGIN_DEVELOPMENT.md — advanced patterns
- PLUGIN_ARCHITECTURE_SPEC.md — original plugin-system design spec (historical; see its banner for what has drifted)
- PLUGIN_DEPENDENCY_GUIDE.md / PLUGIN_DEPENDENCY_TROUBLESHOOTING.md
- PLUGIN_WEB_UI_ACTIONS.md (+ example JSON)
- PLUGIN_CUSTOM_ICONS.md
- PLUGIN_REGISTRY_SETUP_GUIDE.md (+ registry template)
- STARLARK_APPS_GUIDE.md — Starlark-based mini-apps
- widget-guide.md — widget development
- ADAPTIVE_LAYOUT.md — render legibly on any panel size (opt-in font/layout scaling)
- plugin-safety-harness.md — test a plugin across every screen and matrix size
Configuring plugins
- PLUGIN_CONFIG_QUICK_START.md — minimal config you need
- PLUGIN_CONFIGURATION_GUIDE.md — schema design
- PLUGIN_CONFIGURATION_TABS.md — multi-tab UI configs
- PLUGIN_CONFIG_ARCHITECTURE.md — how the config system works
- PLUGIN_CONFIG_CORE_PROPERTIES.md — properties every plugin honors
Advanced features
- ADVANCED_FEATURES.md — Vegas scroll, on-demand display, cache management, background services, permissions
- FONT_MANAGER.md — font system
- SKIN_SYSTEM.md — skin architecture for sports scoreboards
- CREATING_SKINS.md — writing and validating a skin
Reference
- CONFIG_REFERENCE.md — every key in config.json and config_secrets.json
- REST_API_REFERENCE.md — all web-interface HTTP endpoints
- PLUGIN_API_REFERENCE.md — Python APIs available to plugins
- DEVELOPER_QUICK_REFERENCE.md — common dev tasks
- PLUGIN_IMPLEMENTATION_SUMMARY.md — what the plugin system actually does
Contributing to LEDMatrix itself
- DEVELOPMENT.md — environment setup
- HOW_TO_RUN_TESTS.md — running the test suite
- MULTI_ROOT_WORKSPACE_SETUP.md — multi-repo workspace
- MIGRATION_GUIDE.md — breaking changes between releases
- SPORTS_UNIFICATION.md — how the sports scoreboard base classes are organized
Archive
docs/archive/ holds older guides that have been superseded or describe
features that have been removed. They are kept for historical context and
git history but should not be relied on.
Contributing to the docs
- Markdown only, professional tone, minimal emoji.
- Prefer adding to an existing page over creating a new one. If you add a new page, link it from this index in the section it belongs to.
- If a page becomes obsolete, move it to
docs/archive/rather than deleting it, so links don't rot. - Keep examples runnable — paths, commands, and config keys here should match what's actually in the repo.