Files
basic1/display/low_level_display_st7796.h
Adolfo Reyna eacc03a38c Implement 4-quadrant dirty rectangle optimization and 30 FPS limiting for ST7796
Add intelligent partial screen update system using bitwise XOR change detection
and 4-quadrant tracking (top-left, top-right, bottom-left, bottom-right). Each
changed pixel is routed to its quadrant, with sophisticated merge logic that
combines adjacent rectangles when beneficial (<40% overhead). This dramatically
reduces SPI bandwidth for UIs with scattered updates (e.g., corners, sidebars).

Key changes:
- 4-quadrant dirty rectangle tracking with automatic merging
- XOR-based change detection for fast byte-level comparison
- Expose st7796_set_window() for partial region updates
- 30 FPS frame rate limiter (33ms per frame) to prevent excessive refreshes
- Smart sleep timing when frame rate limit is active

Performance: Up to 99% reduction in SPI traffic for corner-based UIs
(e.g., 4 small regions vs full 480x320 screen updates).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-02-11 12:56:10 -05:00

118 lines
3.7 KiB
C++

#ifndef LOW_LEVEL_DISPLAY_ST7796_H
#define LOW_LEVEL_DISPLAY_ST7796_H
#include "low_level_display.h"
#include "st7796.h"
#include <climits>
class LowLevelDisplayST7796 : public LowLevelDisplay {
private:
const st7796_config* config;
int width;
int height;
bool initialized;
uint16_t* rgb_buffer; // Persistent buffer for 1-bit to RGB565 conversion
bool invert_color; // If true, swap black/white
// Dirty rectangle tracking for partial updates
uint8_t* prev_bit_buffer; // Previous frame buffer for change detection
bool dirty_rect_enabled; // Enable/disable dirty rectangle optimization
struct DirtyRect {
int x0, y0; // Top-left corner
int x1, y1; // Bottom-right corner (inclusive)
bool is_valid;
void reset() {
x0 = INT_MAX;
y0 = INT_MAX;
x1 = -1;
y1 = -1;
is_valid = false;
}
void expand(int x, int y) {
if (x < x0) x0 = x;
if (x > x1) x1 = x;
if (y < y0) y0 = y;
if (y > y1) y1 = y;
is_valid = true;
}
int get_width() const { return is_valid ? (x1 - x0 + 1) : 0; }
int get_height() const { return is_valid ? (y1 - y0 + 1) : 0; }
int get_area() const { return is_valid ? get_width() * get_height() : 0; }
bool overlaps(const DirtyRect& other) const {
if (!is_valid || !other.is_valid) return false;
return !(x1 < other.x0 || x0 > other.x1 || y1 < other.y0 || y0 > other.y1);
}
void merge(const DirtyRect& other) {
if (!other.is_valid) return;
if (!is_valid) {
*this = other;
return;
}
x0 = (x0 < other.x0) ? x0 : other.x0;
y0 = (y0 < other.y0) ? y0 : other.y0;
x1 = (x1 > other.x1) ? x1 : other.x1;
y1 = (y1 > other.y1) ? y1 : other.y1;
}
};
static constexpr int MAX_DIRTY_RECTS = 4;
DirtyRect dirty_rects[MAX_DIRTY_RECTS]; // Support up to 4 dirty rectangles (4 quadrants)
public:
LowLevelDisplayST7796(const st7796_config* cfg, int w, int h, bool invert = false);
~LowLevelDisplayST7796() override;
// Core display operations - converts 1-bit to RGB565 internally
bool init() override;
void clear(bool white = true) override;
void draw_pixel(int x, int y, bool white) override;
void draw_buffer(const uint8_t* bit_buffer) override;
void refresh() override;
// Display properties
int get_width() const override { return width; }
int get_height() const override { return height; }
DisplayType get_type() const override { return DISPLAY_TYPE_ST7796; }
bool is_color() const override { return true; }
// Backlight control
void set_backlight(bool on) override;
// Brightness control (0-100)
void set_brightness(uint8_t brightness) override;
uint8_t get_brightness() const override;
// Power management
void sleep(); // Put display to sleep (low power, touch still active)
void wake(); // Wake display from sleep
// Orientation control
void set_rotation(uint8_t rotation) override;
// Color inversion control
void set_invert_color(bool inv) { invert_color = inv; }
bool get_invert_color() const { return invert_color; }
// Power saving hooks
void on_idle_2min() override;
void on_idle_10min() override;
void on_user_interaction() override;
// Dirty rectangle optimization control
void enable_dirty_rect(bool enabled = true);
bool is_dirty_rect_enabled() const { return dirty_rect_enabled; }
private:
uint8_t saved_brightness = 100;
bool is_dimmed = false;
bool is_sleeping = false;
};
#endif // LOW_LEVEL_DISPLAY_ST7796_H