From 43287b920abb5e7de68421417eea7733903fb9de Mon Sep 17 00:00:00 2001 From: bkleiner Date: Sat, 8 Feb 2025 12:17:05 +0100 Subject: [PATCH] osd: optimze screen refresh --- src/driver/osd/displayport.c | 26 ++++---- src/driver/osd/displayport.h | 4 +- src/driver/osd/max7456.c | 6 +- src/driver/osd/max7456.h | 4 +- src/driver/osd/osd.c | 123 +++++++++++++++-------------------- src/io/simulator.c | 8 ++- src/io/simulator.h | 4 +- src/osd/render.c | 3 +- 8 files changed, 80 insertions(+), 98 deletions(-) diff --git a/src/driver/osd/displayport.c b/src/driver/osd/displayport.c index 0895af8ab..71c16d580 100644 --- a/src/driver/osd/displayport.c +++ b/src/driver/osd/displayport.c @@ -51,7 +51,6 @@ serial_port_t serial_displayport = { }; static const uint8_t msp_options[2] = {0, 1}; -static volatile uint32_t last_heartbeat = 0; static bool is_detected = false; static void displayport_msp_send(msp_magic_t magic, uint8_t direction, uint16_t cmd, const uint8_t *data, uint16_t len) { @@ -193,7 +192,8 @@ static void displayport_wait_for_ready() { void displayport_intro() { displayport_wait_for_ready(); - displayport_clear_async(); + while (!displayport_clear_async()) + ; uint8_t buffer[24]; for (uint8_t row = 0; row < 4; row++) { @@ -202,24 +202,22 @@ void displayport_intro() { buffer[i] = start + i; } displayport_wait_for_ready(); - displayport_push_string(OSD_ATTR_TEXT, (DISPLAYPORT_COLS / 2) - 12, (DISPLAYPORT_ROWS / 2) - 2 + row, buffer, 24); + while (!displayport_push_string(OSD_ATTR_TEXT, (DISPLAYPORT_COLS / 2) - 12, (DISPLAYPORT_ROWS / 2) - 2 + row, buffer, 24)) + ; } - displayport_push_subcmd(SUBCMD_DRAW_SCREEN, NULL, 0); + while (displayport_push_subcmd(SUBCMD_DRAW_SCREEN, NULL, 0)) + ; } -uint8_t displayport_clear_async() { +bool displayport_clear_async() { displayport_push_subcmd(SUBCMD_SET_OPTIONS, msp_options, 2); return displayport_push_subcmd(SUBCMD_CLEAR_SCREEN, NULL, 0); } bool displayport_is_ready() { - while (true) { - uint8_t data = 0; - if (!serial_read_bytes(&serial_displayport, &data, 1)) { - break; - } - + uint8_t data = 0; + while (serial_read_byte(&serial_displayport, &data)) { msp_process_serial(&displayport_msp, data); } @@ -230,6 +228,7 @@ bool displayport_is_ready() { return false; } + static uint32_t last_heartbeat = 0; if ((time_millis() - last_heartbeat) > 500) { displayport_push_subcmd(SUBCMD_HEARTBEAT, NULL, 0); last_heartbeat = time_millis(); @@ -254,9 +253,10 @@ bool displayport_push_string(uint8_t attr, uint8_t x, uint8_t y, const uint8_t * return displayport_push_subcmd(SUBCMD_WRITE_STRING, buffer, size + 3); } -bool displayport_can_fit(uint8_t size) { +uint8_t displayport_can_fit() { const uint32_t free = serial_bytes_free(&serial_displayport); - return free > (size + 10); + const uint32_t overhead = MSP_HEADER_LEN + 2 + 3 + 1; + return (free > overhead) ? (free - overhead) : 0; } bool displayport_flush() { diff --git a/src/driver/osd/displayport.h b/src/driver/osd/displayport.h index e2bd1e8e6..0cab11faf 100644 --- a/src/driver/osd/displayport.h +++ b/src/driver/osd/displayport.h @@ -8,9 +8,9 @@ void displayport_init(); bool displayport_is_ready(); void displayport_intro(); -uint8_t displayport_clear_async(); +bool displayport_clear_async(); osd_system_t displayport_check_system(); -bool displayport_can_fit(uint8_t size); +uint8_t displayport_can_fit(); bool displayport_push_string(uint8_t attr, uint8_t x, uint8_t y, const uint8_t *data, uint8_t size); bool displayport_flush(); \ No newline at end of file diff --git a/src/driver/osd/max7456.c b/src/driver/osd/max7456.c index cf357710f..9ac3ea345 100644 --- a/src/driver/osd/max7456.c +++ b/src/driver/osd/max7456.c @@ -135,7 +135,7 @@ static osd_system_t max7456_current_system() { return OSD_SYS_NONE; } -uint8_t max7456_clear_async() { +bool max7456_clear_async() { if (!max7456_is_ready()) { return 0; } @@ -203,8 +203,8 @@ void max7456_intro() { } } -bool max7456_can_fit(uint8_t size) { - return max7456_is_ready(); +uint8_t max7456_can_fit() { + return max7456_is_ready() ? 255 : 0; } bool max7456_push_string(uint8_t attr, uint8_t x, uint8_t y, const uint8_t *data, uint8_t size) { diff --git a/src/driver/osd/max7456.h b/src/driver/osd/max7456.h index 167b48fcc..5d701a461 100644 --- a/src/driver/osd/max7456.h +++ b/src/driver/osd/max7456.h @@ -46,10 +46,10 @@ bool max7456_init(); bool max7456_is_ready(); void max7456_intro(); -uint8_t max7456_clear_async(); +bool max7456_clear_async(); osd_system_t max7456_check_system(); -bool max7456_can_fit(uint8_t size); +uint8_t max7456_can_fit(); bool max7456_push_string(uint8_t attr, uint8_t x, uint8_t y, const uint8_t *data, uint8_t size); bool max7456_flush(); diff --git a/src/driver/osd/osd.c b/src/driver/osd/osd.c index 729a43d15..fab103ed0 100644 --- a/src/driver/osd/osd.c +++ b/src/driver/osd/osd.c @@ -14,12 +14,17 @@ static osd_segment_t osd_seg; static osd_device_t osd_device = OSD_DEVICE_NONE; static osd_char_t display[MAX_DISPLAY_SIZE]; -static bool display_row_dirty[HD_ROWS]; -static bool display_dirty = false; +static uint32_t display_dirty = 0; static uint8_t cols = HD_COLS; static uint8_t rows = HD_ROWS; +#define display_dirty_bit (1 << 31) + +#define display_is_row_dirty(index) ((display_dirty >> (index)) & 0x1) +#define display_mark_row_dirty(index) (display_dirty |= ((1 << (index)) | display_dirty_bit)) +#define display_clear_row_dirty(index) (display_dirty &= ~(1 << (index))) + void osd_device_init() { #ifdef USE_DIGITAL_VTX if (profile.serial.hdzero != SERIAL_PORT_INVALID) { @@ -110,30 +115,13 @@ static bool osd_device_clear_async() { } bool osd_mark_dirty() { - static uint8_t state = 0; - - switch (state) { - case 0: - for (uint32_t i = 0; i < MAX_DISPLAY_SIZE; i++) { - if (display[i].val != ' ') { - display[i].dirty = 1; - } - } - memset(display_row_dirty, 1, HD_ROWS * sizeof(bool)); - display_dirty = true; - state++; - return false; - - case 1: - if (osd_device_clear_async()) { - state++; + for (uint32_t i = 0; i < MAX_DISPLAY_SIZE; i++) { + if (display[i].val != ' ') { + display_mark_row_dirty(i / cols); + display[i].dirty = 1; } - return false; - - default: - state = 0; - return true; } + return true; } bool osd_clear_async() { @@ -143,8 +131,7 @@ bool osd_clear_async() { for (uint32_t i = 0; i < (MAX_DISPLAY_SIZE / 2); i++) { ((uint32_t *)display)[i] = ((0x20 << 16) | 0x20); } - memset(display_row_dirty, 0, HD_ROWS * sizeof(bool)); - display_dirty = false; + display_dirty = 0; state++; return false; } @@ -172,8 +159,7 @@ static void osd_display_set(uint8_t x, uint8_t y, uint8_t attr, uint8_t val) { c->attr = attr; c->val = val; - display_row_dirty[offset / cols] = true; - display_dirty = true; + display_mark_row_dirty(offset / cols); } void osd_display_refresh() { @@ -226,19 +212,19 @@ void osd_write_data(const uint8_t *buffer, uint8_t size) { osd_write_char(buffer[i]); } -static bool osd_can_fit(uint8_t size) { +static uint8_t osd_can_fit() { switch (osd_device) { #ifdef USE_MAX7456 case OSD_DEVICE_MAX7456: - return max7456_can_fit(size); + return max7456_can_fit(); #endif #ifdef USE_DIGITAL_VTX case OSD_DEVICE_DISPLAYPORT: - return displayport_can_fit(size); + return displayport_can_fit(); #endif #ifdef SIMULATOR case OSD_DEVICE_SIMULATOR: - return simulator_osd_can_fit(size); + return simulator_osd_can_fit(); #endif default: return false; @@ -291,63 +277,56 @@ static bool osd_update_display() { static uint8_t row = 0; while (row < rows) { - if (!display_row_dirty[row]) { + if (!display_is_row_dirty(row)) { row++; continue; } + uint8_t start = 0; + uint8_t max_size = osd_can_fit(); uint8_t string[DISPLAYPORT_COLS]; - uint8_t attr = 0; - uint8_t start = cols; - uint8_t size = 0; - - uint8_t col = 0; - for (; col < cols; col++) { - osd_char_t *entry = &display[row * cols + col]; - if (!entry->dirty) { - osd_push_string(attr, start, row, string, size); - size = 0; - start = cols; - continue; - } + osd_char_t *entry = &display[row * cols]; - if (!osd_can_fit(size + 1)) { - break; + while (start < cols) { + if (max_size == 0) { + return false; } - if (col < start) { - start = col; - attr = entry->attr; + // find start + while (!entry->dirty) { + if (start++ >= cols) { + goto osd_finish_row; + } + entry++; } - if (entry->attr != attr && size != 0) { - osd_push_string(attr, start, row, string, size); - attr = entry->attr; - start += size; - size = 0; + uint8_t size = 0; + uint8_t attr = entry->attr; + + while (size < max_size && (start + size) < cols && + entry->dirty && entry->attr == attr) { + string[size] = entry->val; + entry->dirty = 0; + size++; + entry++; } - string[size] = entry->val; - entry->dirty = 0; - size++; - } + osd_push_string(attr, start, row, string, size); - osd_push_string(attr, start, row, string, size); - if (col == cols) { - display_row_dirty[row] = false; - row++; + start += size; + max_size -= size; } - return false; - } - if (row == rows) { - if (osd_flush()) { - row++; - } + osd_finish_row: + display_clear_row_dirty(row); + row++; return false; } - row = 0; + if (osd_flush()) { + row = 0; + return true; + } return true; } @@ -373,7 +352,7 @@ bool osd_is_ready() { bool osd_update() { if (display_dirty) { if (osd_update_display()) { - display_dirty = false; + display_dirty = 0; } return false; } diff --git a/src/io/simulator.c b/src/io/simulator.c index 36bc8538f..91a62e3c5 100644 --- a/src/io/simulator.c +++ b/src/io/simulator.c @@ -138,7 +138,7 @@ void simulator_osd_intro() { simulator_update(); } -uint8_t simulator_osd_clear_async() { +bool simulator_osd_clear_async() { memset(osd, ' ', sizeof(osd)); return 1; } @@ -146,15 +146,17 @@ osd_system_t simulator_osd_check_system() { return OSD_SYS_HD; } -bool simulator_osd_can_fit(uint8_t size) { - return true; +uint8_t simulator_osd_can_fit() { + return 255; } + bool simulator_osd_push_string(uint8_t attr, uint8_t x, uint8_t y, const uint8_t *data, uint8_t size) { for (uint32_t i = 0; i < size; i++) { osd[y * 50 + x + i] = data[i]; } return true; } + bool simulator_osd_flush() { return true; } diff --git a/src/io/simulator.h b/src/io/simulator.h index 065e651a2..f804f334d 100644 --- a/src/io/simulator.h +++ b/src/io/simulator.h @@ -11,9 +11,9 @@ void simulator_osd_init(); bool simulator_osd_is_ready(); void simulator_osd_intro(); -uint8_t simulator_osd_clear_async(); +bool simulator_osd_clear_async(); osd_system_t simulator_osd_check_system(); -bool simulator_osd_can_fit(uint8_t size); +uint8_t simulator_osd_can_fit(); bool simulator_osd_push_string(uint8_t attr, uint8_t x, uint8_t y, const uint8_t *data, uint8_t size); bool simulator_osd_flush(); \ No newline at end of file diff --git a/src/osd/render.c b/src/osd/render.c index b044dd1dd..a112b1f3d 100644 --- a/src/osd/render.c +++ b/src/osd/render.c @@ -399,6 +399,7 @@ static void print_osd_vtx(osd_element_t *el) { void osd_init() { osd_device_init(); + osd_clear(); osd_intro(); osd_update_screen(OSD_SCREEN_CLEAR); } @@ -657,7 +658,7 @@ void osd_display() { } static uint32_t last_redraw = 0; - if ((time_millis() - last_redraw) > 1000) { + if (sys == OSD_SYS_HD && (time_millis() - last_redraw) > 1000) { if (osd_mark_dirty()) { last_redraw = time_millis(); }