From b63a9b23e712800f7f7d0d4269e88c91cf3ed830 Mon Sep 17 00:00:00 2001 From: Tom Hoenderdos Date: Tue, 29 Sep 2026 20:02:33 +0200 Subject: [PATCH] Optimize display list walk to one pass To find how far an item may draw from a pixel, every renderer called *_find_max_line_len(), which scanned all the items above the drawn one again. Each draw call walked the item list twice, and a long display list cost time proportional to the square of its length on every run of pixels. The item loop in the DCS LCD, mono, e-paper and SDL renderers now keeps that limit as a running minimum while it walks the items once: an item above that starts further right on the row shortens the run, as before. The output is unchanged. The *_find_max_line_len() functions are removed. The scaled_cropped_image renderers also stop reducing the item width to the remaining source image, since the parser already does so. Co-Authored-By: Claude Opus 5.5 (1M context) Signed-off-by: Tom Hoenderdos --- dcs_lcd_draw.c | 36 +++++++++++++----------------------- dcs_lcd_draw.h | 3 --- epaper_draw.c | 36 +++++++++++++----------------------- epaper_draw.h | 3 --- mono_draw.c | 36 +++++++++++++----------------------- mono_draw.h | 3 --- sdl_display/display.c | 33 ++++++++++++--------------------- 7 files changed, 51 insertions(+), 99 deletions(-) diff --git a/dcs_lcd_draw.c b/dcs_lcd_draw.c index 80438c1..49e888f 100644 --- a/dcs_lcd_draw.c +++ b/dcs_lcd_draw.c @@ -29,23 +29,6 @@ #include "dcs_lcd_color.h" #include "font_data.h" -int dcs_lcd_find_max_line_len(const struct DCSLCDScreen *screen, - BaseDisplayItem items[], size_t items_len, int xpos, int ypos) -{ - int line_len = screen->w - xpos; - - for (size_t i = 0; i < items_len; i++) { - BaseDisplayItem *item = &items[i]; - - if ((xpos < item->x) && (ypos >= item->y) && (ypos < item->y + item->height)) { - int len_to_item = item->x - xpos; - line_len = (line_len > len_to_item) ? len_to_item : line_len; - } - } - - return line_len; -} - int dcs_lcd_draw_image_x(const struct DCSLCDScreen *screen, int xpos, int ypos, int max_line_len, BaseDisplayItem *item) { @@ -201,10 +184,6 @@ int dcs_lcd_draw_scaled_cropped_img_x(const struct DCSLCDScreen *screen, uint32_t *pixels = ((uint32_t *) data) + (source_y + ((ypos - y) / y_scale)) * img_width + source_x + ((xpos - x) / x_scale); uint16_t *pixmem16 = (uint16_t *) (((uint8_t *) screen->pixels) + xpos * sizeof(uint16_t)); - if (source_x + (width / x_scale) > img_width) { - width = (img_width - source_x) * x_scale; - } - if (width > xpos - x + max_line_len) { width = xpos - x + max_line_len; } @@ -232,15 +211,26 @@ int dcs_lcd_draw_scaled_cropped_img_x(const struct DCSLCDScreen *screen, int dcs_lcd_draw_x(const struct DCSLCDScreen *screen, int xpos, int ypos, BaseDisplayItem items[], size_t items_len) { + int line_len = screen->w - xpos; bool below = false; for (size_t i = 0; i < items_len; i++) { BaseDisplayItem *item = &items[i]; - if ((xpos < item->x) || (xpos >= item->x + item->width) || (ypos < item->y) || (ypos >= item->y + item->height)) { + if ((ypos < item->y) || (ypos >= item->y + item->height)) { + continue; + } + if (xpos < item->x) { + int len_to_item = item->x - xpos; + if (len_to_item < line_len) { + line_len = len_to_item; + } + continue; + } + if (xpos >= item->x + item->width) { continue; } - int max_line_len = below ? 1 : dcs_lcd_find_max_line_len(screen, items, i, xpos, ypos); + int max_line_len = below ? 1 : line_len; int drawn_pixels = 0; switch (items[i].primitive) { diff --git a/dcs_lcd_draw.h b/dcs_lcd_draw.h index a99b407..6a79e1d 100644 --- a/dcs_lcd_draw.h +++ b/dcs_lcd_draw.h @@ -36,9 +36,6 @@ int dcs_lcd_draw_text_x(const struct DCSLCDScreen *screen, int dcs_lcd_draw_scaled_cropped_img_x(const struct DCSLCDScreen *screen, int xpos, int ypos, int max_line_len, BaseDisplayItem *item); -int dcs_lcd_find_max_line_len(const struct DCSLCDScreen *screen, - BaseDisplayItem items[], size_t items_len, int xpos, int ypos); - int dcs_lcd_draw_x(const struct DCSLCDScreen *screen, int xpos, int ypos, BaseDisplayItem items[], size_t items_len); diff --git a/epaper_draw.c b/epaper_draw.c index 0d8c4d1..c90d2ed 100644 --- a/epaper_draw.c +++ b/epaper_draw.c @@ -46,23 +46,6 @@ void epaper_draw_pixel_x(const struct EpaperScreen *screen, } } -int epaper_find_max_line_len(const struct EpaperScreen *screen, - BaseDisplayItem items[], size_t items_len, int xpos, int ypos) -{ - int line_len = screen->w - xpos; - - for (size_t i = 0; i < items_len; i++) { - BaseDisplayItem *item = &items[i]; - - if ((xpos < item->x) && (ypos >= item->y) && (ypos < item->y + item->height)) { - int len_to_item = item->x - xpos; - line_len = (line_len > len_to_item) ? len_to_item : line_len; - } - } - - return line_len; -} - int epaper_draw_image_x(const struct EpaperScreen *screen, uint8_t *line_buf, int xpos, int ypos, int max_line_len, BaseDisplayItem *item) @@ -259,10 +242,6 @@ int epaper_draw_scaled_cropped_img_x(const struct EpaperScreen *screen, uint32_t *pixels = ((uint32_t *) data) + (source_y + ((ypos - y) / y_scale)) * img_width + source_x + ((xpos - x) / x_scale); - if (source_x + (width / x_scale) > img_width) { - width = (img_width - source_x) * x_scale; - } - if (width > xpos - x + max_line_len) { width = xpos - x + max_line_len; } @@ -297,15 +276,26 @@ int epaper_draw_x(const struct EpaperScreen *screen, uint8_t *line_buf, int xpos, int ypos, BaseDisplayItem items[], size_t items_len) { + int line_len = screen->w - xpos; bool below = false; for (size_t i = 0; i < items_len; i++) { BaseDisplayItem *item = &items[i]; - if ((xpos < item->x) || (xpos >= item->x + item->width) || (ypos < item->y) || (ypos >= item->y + item->height)) { + if ((ypos < item->y) || (ypos >= item->y + item->height)) { + continue; + } + if (xpos < item->x) { + int len_to_item = item->x - xpos; + if (len_to_item < line_len) { + line_len = len_to_item; + } + continue; + } + if (xpos >= item->x + item->width) { continue; } - int max_line_len = below ? 1 : epaper_find_max_line_len(screen, items, i, xpos, ypos); + int max_line_len = below ? 1 : line_len; int drawn_pixels = 0; switch (items[i].primitive) { diff --git a/epaper_draw.h b/epaper_draw.h index 22df4d0..3fb5a28 100644 --- a/epaper_draw.h +++ b/epaper_draw.h @@ -43,9 +43,6 @@ int epaper_draw_scaled_cropped_img_x(const struct EpaperScreen *screen, uint8_t *line_buf, int xpos, int ypos, int max_line_len, BaseDisplayItem *item); -int epaper_find_max_line_len(const struct EpaperScreen *screen, - BaseDisplayItem items[], size_t items_len, int xpos, int ypos); - int epaper_draw_x(const struct EpaperScreen *screen, uint8_t *line_buf, int xpos, int ypos, BaseDisplayItem items[], size_t items_len); diff --git a/mono_draw.c b/mono_draw.c index ed797d2..5fa278f 100644 --- a/mono_draw.c +++ b/mono_draw.c @@ -77,23 +77,6 @@ void mono_draw_pixel_x(const struct MonoScreen *screen, line_buf[xpos / 8] = (line_buf[xpos / 8] & ~(0x1 << bpos)) | (color << bpos); } -int mono_find_max_line_len(const struct MonoScreen *screen, - BaseDisplayItem items[], size_t items_len, int xpos, int ypos) -{ - int line_len = screen->w - xpos; - - for (size_t i = 0; i < items_len; i++) { - BaseDisplayItem *item = &items[i]; - - if ((xpos < item->x) && (ypos >= item->y) && (ypos < item->y + item->height)) { - int len_to_item = item->x - xpos; - line_len = (line_len > len_to_item) ? len_to_item : line_len; - } - } - - return line_len; -} - int mono_draw_image_x(const struct MonoScreen *screen, uint8_t *line_buf, int xpos, int ypos, int max_line_len, BaseDisplayItem *item) @@ -286,10 +269,6 @@ int mono_draw_scaled_cropped_img_x(const struct MonoScreen *screen, uint32_t *pixels = ((uint32_t *) data) + (source_y + ((ypos - y) / y_scale)) * img_width + source_x + ((xpos - x) / x_scale); - if (source_x + (width / x_scale) > img_width) { - width = (img_width - source_x) * x_scale; - } - if (width > xpos - x + max_line_len) { width = xpos - x + max_line_len; } @@ -322,15 +301,26 @@ int mono_draw_x(const struct MonoScreen *screen, uint8_t *line_buf, int xpos, int ypos, BaseDisplayItem items[], size_t items_len) { + int line_len = screen->w - xpos; bool below = false; for (size_t i = 0; i < items_len; i++) { BaseDisplayItem *item = &items[i]; - if ((xpos < item->x) || (xpos >= item->x + item->width) || (ypos < item->y) || (ypos >= item->y + item->height)) { + if ((ypos < item->y) || (ypos >= item->y + item->height)) { + continue; + } + if (xpos < item->x) { + int len_to_item = item->x - xpos; + if (len_to_item < line_len) { + line_len = len_to_item; + } + continue; + } + if (xpos >= item->x + item->width) { continue; } - int max_line_len = below ? 1 : mono_find_max_line_len(screen, items, i, xpos, ypos); + int max_line_len = below ? 1 : line_len; int drawn_pixels = 0; switch (items[i].primitive) { diff --git a/mono_draw.h b/mono_draw.h index 0cda8c8..97e0497 100644 --- a/mono_draw.h +++ b/mono_draw.h @@ -48,9 +48,6 @@ int mono_draw_scaled_cropped_img_x(const struct MonoScreen *screen, uint8_t *line_buf, int xpos, int ypos, int max_line_len, BaseDisplayItem *item); -int mono_find_max_line_len(const struct MonoScreen *screen, - BaseDisplayItem items[], size_t items_len, int xpos, int ypos); - int mono_draw_x(const struct MonoScreen *screen, uint8_t *line_buf, int xpos, int ypos, BaseDisplayItem items[], size_t items_len); diff --git a/sdl_display/display.c b/sdl_display/display.c index c6760d2..f096534 100644 --- a/sdl_display/display.c +++ b/sdl_display/display.c @@ -302,10 +302,6 @@ static int draw_scaled_cropped_img_x(int xpos, int ypos, int max_line_len, BaseD uint32_t *pixels = ((uint32_t *) data) + (source_y + ((ypos - y) / y_scale)) * img_width + source_x + ((xpos - x) / x_scale); Uint32 *pixmem32 = (Uint32 *) (((uint8_t *) screen->pixels) + screen->w * ypos * BPP + xpos * BPP); - if (source_x + (width / x_scale) > img_width) { - width = (img_width - source_x) * x_scale; - } - if (width > xpos - x + max_line_len) { width = xpos - x + max_line_len; } @@ -403,33 +399,28 @@ static int draw_text_x(int xpos, int ypos, int max_line_len, BaseDisplayItem *it return drawn_pixels; } -static int find_max_line_len(BaseDisplayItem items[], size_t items_len, int xpos, int ypos) +static int draw_x(int xpos, int ypos, BaseDisplayItem items[], size_t items_len) { int line_len = screen->w - xpos; + bool below = false; for (size_t i = 0; i < items_len; i++) { BaseDisplayItem *item = &items[i]; - - if ((xpos < item->x) && (ypos >= item->y) && (ypos < item->y + item->height)) { + if ((ypos < item->y) || (ypos >= item->y + item->height)) { + continue; + } + if (xpos < item->x) { int len_to_item = item->x - xpos; - line_len = (line_len > len_to_item) ? len_to_item : line_len; + if (len_to_item < line_len) { + line_len = len_to_item; + } + continue; } - } - - return line_len; -} - -static int draw_x(int xpos, int ypos, BaseDisplayItem items[], size_t items_len) -{ - bool below = false; - - for (size_t i = 0; i < items_len; i++) { - BaseDisplayItem *item = &items[i]; - if ((xpos < item->x) || (xpos >= item->x + item->width) || (ypos < item->y) || (ypos >= item->y + item->height)) { + if (xpos >= item->x + item->width) { continue; } - int max_line_len = below ? 1 : find_max_line_len(items, i, xpos, ypos); + int max_line_len = below ? 1 : line_len; int drawn_pixels = 0; switch (items[i].primitive) {