display: optimize double-buffered icon drawing
What changed, and why it matters
This commit is a performance optimization for drawing small icons on the Blockstream Jade hardware wallet screen. It replaces a helper function call that reads one pixel at a time with faster inline code that reads icon data in 32-bit chunks. There is no indication in the commit or supplied references that this fixes a security bug.
No security action required. Treat as a normal performance refactor.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change refactors display_icon() in main/display.c to avoid per-pixel get_icon_pixel() calls and instead stream through imgbuf->data as 32-bit words, consuming one bit per pixel. It preserves the same behavior for foreground color, optional background color, and transparency. The diff is purely a drawing optimization; no bounds checks, input validation, or memory safety semantics appear to change.
Changed components
main/display.cdisplay_icon()Inspect captured patch +24 / −9
diff --git a/main/display.c b/main/display.c
index 9382364..a4edae3 100644
--- a/main/display.c
+++ b/main/display.c
@@ -500,18 +500,33 @@ void display_icon(const Icon* imgbuf, int x, int y, color_t color, dispWin_t are
const int calculatedx = x - CONFIG_DISPLAY_OFFSET_X;
const int calculatedy = y - CONFIG_DISPLAY_OFFSET_Y;
uint16_t* hw_buf = display_hw_get_buffer();
- uint16_t* screen_ptr = &hw_buf[calculatedx + calculatedy * CONFIG_DISPLAY_WIDTH];
+ uint16_t* disp_ptr = &hw_buf[calculatedx + calculatedy * CONFIG_DISPLAY_WIDTH];
+ const uint32_t* icon_data = imgbuf->data;
+ uint32_t icon_bits = 0, bit_counter = 0;
+ const uint32_t stride = CONFIG_DISPLAY_WIDTH - draw_width;
for (size_t i = 0; i < draw_height; ++i) {
- uint16_t* row_ptr = screen_ptr + i * CONFIG_DISPLAY_WIDTH;
- for (size_t k = 0; k < draw_width; ++k) {
- if (get_icon_pixel(k, i, imgbuf->width, imgbuf)) {
- row_ptr[k] = color;
- } else if (bg_color) {
- row_ptr[k] = *bg_color;
- } else {
- // transparent, skip
+ if (bg_color) {
+ const color_t bg = *bg_color;
+ for (size_t k = 0; k < draw_width; ++k, ++bit_counter) {
+ if (!(bit_counter & 31)) {
+ icon_bits = *icon_data++; // Read next word every 32 bits
+ }
+ *disp_ptr++ = icon_bits & 0x1 ? color : bg;
+ icon_bits >>= 1;
+ }
+ } else {
+ for (size_t k = 0; k < draw_width; ++k, ++bit_counter) {
+ if (!(bit_counter & 31)) {
+ icon_bits = *icon_data++; // Read next word every 32 bits
+ }
+ if (icon_bits & 0x1) {
+ *disp_ptr = color;
+ }
+ ++disp_ptr;
+ icon_bits >>= 1;
}
}
+ disp_ptr += stride;
}
#else
Why this scored 12/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.