From 79fcc8e71592fd9a817ca9b33075c5ffeb87e4ab Mon Sep 17 00:00:00 2001 From: Davide Bettio Date: Mon, 28 Sep 2026 19:10:51 +0000 Subject: [PATCH 1/3] sdl: Fix register_font for ufontlib API ufont_manager_register() takes an owned buffer since 6c0e995, so the plugin did not compile. The font was also parsed from the message binary, which is freed once the call is answered. Signed-off-by: Davide Bettio --- sdl_display/display.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/sdl_display/display.c b/sdl_display/display.c index f096534..96f0458 100644 --- a/sdl_display/display.c +++ b/sdl_display/display.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -566,13 +567,22 @@ static void process_message(Context *ctx) } else if (cmd == globalcontext_make_atom(ctx->global, "\xD" "register_font")) { term font_bin = term_get_tuple_element(req, 2); - EpdFont *loaded_font = ufont_parse(term_binary_data(font_bin), term_binary_size(font_bin)); + size_t font_size = term_binary_size(font_bin); + void *owned_buf = malloc(font_size); + EpdFont *loaded_font = NULL; + if (owned_buf != NULL) { + memcpy(owned_buf, term_binary_data(font_bin), font_size); + loaded_font = ufont_parse(owned_buf, font_size); + if (loaded_font == NULL) { + free(owned_buf); + } + } char *handle = interop_atom_to_string(ctx, term_get_tuple_element(req, 1)); - if (handle != NULL) { - ufont_manager_register(ufont_manager, handle, loaded_font); - free(handle); + if (loaded_font != NULL && handle != NULL) { + ufont_manager_register(ufont_manager, handle, loaded_font, owned_buf); } + free(handle); } else { fprintf(stderr, "unexpected command: "); From 1f1500f2d697cf352cca3a9d1b8b4eaaa54c7864 Mon Sep 17 00:00:00 2001 From: Davide Bettio Date: Mon, 28 Sep 2026 19:10:51 +0000 Subject: [PATCH 2/3] sdl: Fix subscribe_input option index The driver read element 2 of the arity-2 {subscribe_input, Sources} tuple, one past its end. Signed-off-by: Davide Bettio --- sdl_display/display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdl_display/display.c b/sdl_display/display.c index 96f0458..8cf6922 100644 --- a/sdl_display/display.c +++ b/sdl_display/display.c @@ -552,7 +552,7 @@ static void process_message(Context *ctx) if (term_get_tuple_arity(req) != 2) { goto invalid_message; } - term sources = term_get_tuple_element(req, 2); + term sources = term_get_tuple_element(req, 1); if (term_is_pid(keyboard_pid) || sources != globalcontext_make_atom(ctx->global, "\x3" "all")) { fprintf(stderr, "Warning: only one subscriber to all sources is supported now\n"); } From 8a100c6a212149b180b0da07becf3057f9d72a29 Mon Sep 17 00:00:00 2001 From: Davide Bettio Date: Fri, 2 Oct 2026 09:50:51 +0000 Subject: [PATCH 3/3] sdl: Remove the broken damage tracking The comparison between the previous and the new display list had several bugs, and a workaround forced a full redraw anyway. Its only effect left was to skip an update whose list looked unchanged, which the bugs made unreliable. Remove it and always redraw; a damage tracking module shared by all drivers follows in a separate series. See also: #20 Signed-off-by: Davide Bettio --- sdl_display/display.c | 186 ++---------------------------------------- 1 file changed, 9 insertions(+), 177 deletions(-) diff --git a/sdl_display/display.c b/sdl_display/display.c index 8cf6922..1313241 100644 --- a/sdl_display/display.c +++ b/sdl_display/display.c @@ -65,15 +65,6 @@ struct MouseEvent int y; }; -struct Rectangle -{ - int x; - int y; - int width; - int height; - bool valid; -}; - static term keyboard_pid; static struct timespec ts0; Context *the_ctx; @@ -97,10 +88,6 @@ UFontManager *ufont_manager; static NativeHandlerResult consume_display_mailbox(Context *ctx); static void *display_loop(); -Message *prev_message = NULL; -BaseDisplayItem *prev_items = NULL; -int prev_items_len = 0; - static void destroy_message(Message *m, GlobalContext *global) { BEGIN_WITH_STACK_HEAP(1, temp_heap); @@ -108,124 +95,6 @@ static void destroy_message(Message *m, GlobalContext *global) END_WITH_STACK_HEAP(temp_heap, global); } -static inline int int_min(int a, int b) -{ - return (a > b) ? b : a; -} - -static inline int int_max(int a, int b) -{ - return (a > b) ? a : b; -} - -static bool cmp_display_item(BaseDisplayItem *a, BaseDisplayItem *b) -{ - if (a->primitive != b->primitive || a->x != b->x || a->y != b->y || - a->width != b->width || a->height != b->height || a->brcolor != b->brcolor) { - return false; - } - - switch (a->primitive) { - case PrimitiveImage: - return a->data.image_data.pix == b->data.image_data.pix; - - case PrimitiveRect: - return true; - - case PrimitiveText: - return (a->data.text_data.fgcolor == b->data.text_data.fgcolor) && - !strcmp(a->data.text_data.text, b->data.text_data.text); - - case PrimitiveScaledCroppedImage: - return (a->data.image_data.pix == b->data.image_data.pix) && - (a->x_scale == b->x_scale) && (a->y_scale == b->y_scale) && - (a->source_x == b->source_x) && (a->source_y == b->source_y); - - default: { - return true; - } - } -} - -static void update_damaged_area(struct Rectangle *area, const struct Rectangle *damage) -{ - if (area->valid) { - area->x = int_min(area->x, damage->x); - area->y = int_min(area->y, damage->y); - area->width = int_max(area->x + area->width, damage->x + damage->width) - area->x; - area->height = int_max(area->y + area->height, damage->y + damage->height) - area->y; - } else { - area->x = damage->x; - area->y = damage->y; - area->width = damage->width; - area->height = damage->height; - area->valid = true; - } -} - -static void clip_rectangle(struct Rectangle *rectangle, const struct Rectangle *clip_region) -{ - rectangle->x = int_max(rectangle->x, clip_region->x); - rectangle->y = int_max(rectangle->y, clip_region->y); - rectangle->width = int_min(rectangle->x + rectangle->width, clip_region->x + clip_region->width) - rectangle->x; - rectangle->height = int_min(rectangle->y + rectangle->height, clip_region->y + clip_region->height) - rectangle->y; -} - -static void dumb_diff(BaseDisplayItem *orig, int orig_len, BaseDisplayItem *new, int new_len, struct Rectangle *damaged) -{ - if (orig_len == 0) { - for (int i = 0; i < new_len; i++) { - struct Rectangle irect = { - .x = new[i].x, - .y = new[i].y, - .width = new[i].width, - .height = new[i].height, - .valid = true - }; - update_damaged_area(damaged, &irect); - } - return; - } - - int j = 0; - - for (int i = 0; i < new_len; i++) { - if (cmp_display_item(&new[i], &orig[j])) { - j++; - } else { - bool found = false; - for (int k = j + 1; k < orig_len; k++) { - if (cmp_display_item(&new[i], &orig[k])) { - for (int l = k - j; l < k; l++) { - struct Rectangle irect = { - .x = orig[l].x, - .y = orig[l].y, - .width = orig[l].width, - .height = orig[l].height, - .valid = true - }; - update_damaged_area(damaged, &irect); - } - - j = k + 1; - found = true; - break; - } - } - if (!found) { - struct Rectangle irect = { - .x = new[i].x, - .y = new[i].y, - .width = new[i].width, - .height = new[i].height, - .valid = true - }; - update_damaged_area(damaged, &irect); - } - } - } -} - static inline Uint32 uint32_color_to_surface(struct Screen *screen, uint32_t color) { return SDL_MapRGB(screen->format, (color >> 24) & 0xFF, (color >> 16) & 0xFF, (color >> 8) & 0xFF); @@ -456,55 +325,22 @@ static int draw_x(int xpos, int ypos, BaseDisplayItem items[], size_t items_len) return 1; } -static bool do_update(Context *ctx, term display_list) +static void do_update(Context *ctx, term display_list) { BaseDisplayItem *items; size_t len; if (UNLIKELY(display_items_new_list(display_list, &items, &len, ctx) != DisplayItemsOk)) { - return false; - } - - struct Rectangle damaged; - damaged.valid = false; - dumb_diff(prev_items, prev_items_len, items, len, &damaged); - if (prev_message) { - display_items_delete(prev_items, prev_items_len); - destroy_message(prev_message, ctx->global); - } - prev_items = items; - prev_items_len = len; - - if (!damaged.valid) { - // skip update - return true; + return; } - struct Rectangle screen_rect = { - .x = 0, - .y = 0, - .width = screen->w, - .height = screen->h, - .valid = true - }; - clip_rectangle(&damaged, &screen_rect); - - // BUG: damage area is not correct - // WORKAROUND: always damage the whole screen to force full redraw - damaged.x = 0; - damaged.y = 0; - damaged.height = screen->h; - damaged.width = screen->w; - // END OF WORKAROUND - - for (int ypos = damaged.y; ypos < damaged.y + damaged.height; ypos++) { - int xpos = damaged.x; - while (xpos < damaged.x + damaged.width) { - int drawn_pixels = draw_x(xpos, ypos, items, len); - xpos += drawn_pixels; + for (int ypos = 0; ypos < screen->h; ypos++) { + int xpos = 0; + while (xpos < screen->w) { + xpos += draw_x(xpos, ypos, items, len); } } - return true; + display_items_delete(items, len); } static void process_message(Context *ctx) @@ -533,9 +369,7 @@ static void process_message(Context *ctx) if (cmd == globalcontext_make_atom(ctx->global, "\x6" "update")) { term display_list = term_get_tuple_element(req, 1); - if (do_update(ctx, display_list)) { - prev_message = message; - } + do_update(ctx, display_list); // Copy and scale up int scale = screen->scale; @@ -615,9 +449,7 @@ static void process_message(Context *ctx) fprintf(stderr, "Expected gen_server call.\n"); free_msg_and_exit: - if (prev_message != message) { - destroy_message(message, ctx->global); - } + destroy_message(message, ctx->global); return; }