feat: implement 20 FPS render target with dirty checking optimization #320

Merged
freemo merged 3 commits from feature/m2-render-fps into master 2026-03-16 19:54:59 +00:00
Owner

Summary

  • Implement RenderLoop class with 20 FPS target (50ms per frame)
  • Frame timing with sleep compensation for consistent frame rates
  • Frame overrun handling: skip sleep immediately if processing exceeds budget
  • FrameStats tracking for performance monitoring

Implementation Details

  • RenderLoop runs on a dedicated thread, draining RenderOp queue each frame
  • Configurable FPS parameter (default 20)
  • Thread-safe start/stop lifecycle with graceful shutdown
  • Integration with existing DirtyCheckStage for per-window content hashing

Testing

  • 32 unit test scenarios in tests/unit/render_fps.feature
  • 15 integration test scenarios in tests/integration/render_fps_integration.feature
  • All render-related tests pass (98 scenarios, 333 steps)

Files Changed

  • lib/aethyr/core/render/frame_scheduler.rb - New RenderLoop and FrameStats classes
  • tests/unit/render_fps.feature - Unit tests
  • tests/unit/step_definitions/render_fps_steps.rb - Step definitions
  • tests/integration/render_fps_integration.feature - Integration tests
  • tests/integration/step_definitions/render_fps_integration_steps.rb - Step definitions

Closes #308

## Summary - Implement `RenderLoop` class with 20 FPS target (50ms per frame) - Frame timing with sleep compensation for consistent frame rates - Frame overrun handling: skip sleep immediately if processing exceeds budget - `FrameStats` tracking for performance monitoring ## Implementation Details - `RenderLoop` runs on a dedicated thread, draining RenderOp queue each frame - Configurable FPS parameter (default 20) - Thread-safe start/stop lifecycle with graceful shutdown - Integration with existing `DirtyCheckStage` for per-window content hashing ## Testing - 32 unit test scenarios in `tests/unit/render_fps.feature` - 15 integration test scenarios in `tests/integration/render_fps_integration.feature` - All render-related tests pass (98 scenarios, 333 steps) ## Files Changed - `lib/aethyr/core/render/frame_scheduler.rb` - New RenderLoop and FrameStats classes - `tests/unit/render_fps.feature` - Unit tests - `tests/unit/step_definitions/render_fps_steps.rb` - Step definitions - `tests/integration/render_fps_integration.feature` - Integration tests - `tests/integration/step_definitions/render_fps_integration_steps.rb` - Step definitions Closes #308
Implements the RenderOp value object class for the UI render pipeline as
specified in issue #304. RenderOps are immutable value objects that describe
rendering instructions without specifying how they should be rendered.

Key features:
- Immutable value objects (frozen after creation) with type, window, and data
- Seven core RenderOp types: text_append, map_refresh, bar_update,
  prompt_update, window_clear, overlay_show, overlay_hide
- Factory methods for convenient construction: RenderOp.text_append(),
  RenderOp.bar_update(), etc.
- Data validation per type (required fields are enforced)
- Equality comparison support (== and hash for use as hash keys)
- to_h serialization for logging and debugging
- Comprehensive YARD documentation

Testing:
- 36 Cucumber scenarios covering all factory methods, immutability,
  validation, equality, and type constants
- 3 integration scenarios for realistic usage patterns

ISSUES CLOSED: #304
Implement a modular 6-stage render pipeline that processes RenderOps
into terminal output:

1. Router - Routes ops to target windows, groups by window
2. Formatter - Applies ANSI colors, word wrapping to window width
3. Layout - Solves layout constraints for window positions/sizes
4. Dirty Check - Compares against previous frame, marks clean windows
5. Ncurses - Writes dirty windows to ncurses buffers (wnoutrefresh)
6. Composite - Calls doupdate once per frame

Each stage is a separate class for testability. The pipeline handles
empty op batches gracefully (no-op frame) and supports terminal resize.

Includes unit tests covering all 6 stages and integration tests for
the full pipeline flow.
freemo force-pushed feature/m2-render-fps from ea868f6f4e to 8828a401cf 2026-03-16 16:56:56 +00:00 Compare
freemo force-pushed feature/m2-render-fps from 8828a401cf to 7af387f1a0 2026-03-16 17:31:35 +00:00 Compare
freemo force-pushed feature/m2-render-fps from 7af387f1a0 to 0d648cfabb 2026-03-16 19:54:50 +00:00 Compare
freemo merged commit 0d648cfabb into master 2026-03-16 19:54:59 +00:00
freemo deleted branch feature/m2-render-fps 2026-03-16 19:55:00 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: aethyr/Aethyr#320
No description provided.