Skip to content

Commit

Permalink
osd: optimze screen refresh
Browse files Browse the repository at this point in the history
  • Loading branch information
bkleiner committed Feb 9, 2025
1 parent 3f6d61f commit f92ad7b
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 104 deletions.
26 changes: 13 additions & 13 deletions src/driver/osd/displayport.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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++) {
Expand All @@ -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);
}

Expand All @@ -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();
Expand All @@ -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() {
Expand Down
4 changes: 2 additions & 2 deletions src/driver/osd/displayport.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
6 changes: 3 additions & 3 deletions src/driver/osd/max7456.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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) {
Expand Down
4 changes: 2 additions & 2 deletions src/driver/osd/max7456.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
141 changes: 71 additions & 70 deletions src/driver/osd/osd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -109,28 +114,24 @@ static bool osd_device_clear_async() {
return true;
}

bool osd_mark_dirty() {
static bool osd_mark_dirty() {
static uint8_t state = 0;

switch (state) {
case 0:
if (!osd_device_clear_async()) {
return false;
}
state++;
// FALLTHROUGH

default:
for (uint32_t i = 0; i < MAX_DISPLAY_SIZE; i++) {
if (display[i].val != ' ') {
display_mark_row_dirty(i / cols);
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++;
}
return false;

default:
state = 0;
return true;
}
Expand All @@ -139,22 +140,22 @@ bool osd_mark_dirty() {
bool osd_clear_async() {
static uint8_t state = 0;

if (state == 0) {
switch (state) {
case 0:
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;
}

if (!osd_device_clear_async()) {
return false;
default:
if (!osd_device_clear_async()) {
return false;
}
state = 0;
return true;
}

state = 0;
return true;
}

static void osd_display_set(uint8_t x, uint8_t y, uint8_t attr, uint8_t val) {
Expand All @@ -172,8 +173,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() {
Expand Down Expand Up @@ -226,19 +226,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;
Expand Down Expand Up @@ -291,63 +291,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;
}

Expand All @@ -371,9 +364,17 @@ bool osd_is_ready() {
}

bool osd_update() {
static uint32_t last_redraw = 0;
if (osd_device == OSD_DEVICE_DISPLAYPORT &&
!display_dirty && time_millis() - last_redraw > 5000) {
if (osd_mark_dirty()) {
last_redraw = time_millis();
}
return false;
}
if (display_dirty) {
if (osd_update_display()) {
display_dirty = false;
display_dirty = 0;
}
return false;
}
Expand Down
1 change: 0 additions & 1 deletion src/driver/osd/osd.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ bool osd_is_ready();
bool osd_update();

void osd_clear();
bool osd_mark_dirty();
bool osd_clear_async();

void osd_display_refresh();
Expand Down
8 changes: 5 additions & 3 deletions src/io/simulator.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,23 +138,25 @@ void simulator_osd_intro() {
simulator_update();
}

uint8_t simulator_osd_clear_async() {
bool simulator_osd_clear_async() {
memset(osd, ' ', sizeof(osd));
return 1;
}
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;
}
Expand Down
Loading

0 comments on commit f92ad7b

Please sign in to comment.