8000 Track a dirty area for in-memory bitmaps · adafruit/circuitpython@4a6bdb6 · GitHub
[go: up one dir, main page]

Skip to content

Commit 4a6bdb6

Browse files
committed
Track a dirty area for in-memory bitmaps
This fixes the bug that bitmap changes do not cause screen updates and optimizes the refresh when the bitmap is simply shown on the screen. If the bitmap is used in tiles, then changing it will cause all TileGrids using it to do a full refresh. Fixes #1981
1 parent d12e1a8 commit 4a6bdb6

File tree

8 files changed

+83
-11
lines changed

8 files changed

+83
-11
lines changed

shared-bindings/displayio/TileGrid.c

< 8000 button class="Button Button--iconOnly Button--invisible flex-shrink-0 js-expand-all-difflines-button" aria-label="Expand all lines: shared-bindings/displayio/TileGrid.c" data-file-path="shared-bindings/displayio/TileGrid.c" aria-describedby=":R26otlab:">
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,8 @@ STATIC mp_obj_t displayio_tilegrid_make_new(const mp_obj_type_t *type, size_t n_
131131

132132
displayio_tilegrid_t *self = m_new_obj(displayio_tilegrid_t);
133133
self->base.type = &displayio_tilegrid_type;
134-
common_hal_displayio_tilegrid_construct(self, native, bitmap_width / tile_width,
134+
common_hal_displayio_tilegrid_construct(self, native,
135+
bitmap_width / tile_width, bitmap_height / tile_height,
135136
pixel_shader, args[ARG_width].u_int, args[ARG_height].u_int,
136137
tile_width, tile_height, x, y, args[ARG_default_tile].u_int);
137138
return MP_OBJ_FROM_PTR(self);
@@ -346,7 +347,7 @@ STATIC mp_obj_t tilegrid_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t v
346347
}
347348
if (x >= common_hal_displayio_tilegrid_get_width(self) ||
348349
y >= common_hal_displayio_tilegrid_get_height(self)) {
349-
mp_raise_IndexError(translate("tile index out of bounds"));
350+
mp_raise_IndexError(translate("Tile index out of bounds"));
350351
}
351352

352353
if (value_obj == MP_OBJ_SENTINEL) {
@@ -357,7 +358,7 @@ STATIC mp_obj_t tilegrid_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t v
357358
} else {
358359
mp_int_t value = mp_obj_get_int(value_obj);
359360
if (value < 0 || value > 255) {
360-
mp_raise_ValueError(translate("Tile indices must be 0 - 255"));
361+
mp_raise_ValueError(translate("Tile value out of bounds"));
361362
}
362363
common_hal_displayio_tilegrid_set_tile(self, x, y, value);
363364
}

shared-bindings/displayio/TileGrid.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@
3232
extern const mp_obj_type_t displayio_tilegrid_type;
3333

3434
void common_hal_displayio_tilegrid_construct(displayio_tilegrid_t *self, mp_obj_t bitmap,
35-
uint16_t bitmap_width_in_tiles, mp_obj_t pixel_shader, uint16_t width, uint16_t height,
35+
uint16_t bitmap_width_in_tiles, uint16_t bitmap_height_in_tiles,
36+
mp_obj_t pixel_shader, uint16_t width, uint16_t height,
3637
uint16_t tile_width, uint16_t tile_height, uint16_t x, uint16_t y, uint8_t default_tile);
3738

3839
mp_int_t common_hal_displayio_tilegrid_get_x(displayio_tilegrid_t *self);

shared-module/displayio/Bitmap.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ void common_hal_displayio_bitmap_construct(displayio_bitmap_t *self, uint32_t wi
6363
}
6464
self->x_mask = (1 << self->x_shift) - 1; // Used as a modulus on the x value
6565
self->bitmask = (1 << bits_per_value) - 1;
66+
67+
self->dirty_area.x1 = 0;
68+
self->dirty_area.x2 = width;
69+
self->dirty_area.y1 = 0;
70+
self->dirty_area.y2 = height;
6671
}
6772

6873
uint16_t common_hal_displayio_bitmap_get_height(displayio_bitmap_t *self) {
@@ -104,6 +109,26 @@ void common_hal_displayio_bitmap_set_pixel(displayio_bitmap_t *self, int16_t x,
104109
if (self->read_only) {
105110
mp_raise_RuntimeError(translate("Read-only object"));
106111
}
112+
// Update the dirty area.
113+
if (self->dirty_area.x1 == self->dirty_area.x2) {
114+
self->dirty_area.x1 = x;
115+
self->dirty_area.x2 = x + 1;
116+
self->dirty_area.y1 = y;
117+
self->dirty_area.y2 = y + 1;
118+
} else {
119+
if (x < self->dirty_area.x1) {
120+
self->dirty_area.x1 = x;
121+
} else if (x >= self->dirty_area.x2) {
122+
self->dirty_area.x2 = x + 1;
123+
}
124+
if (y < self->dirty_area.y1) {
125+
self->dirty_area.y1 = y;
126+
} else if (y >= self->dirty_area.y2) {
127+
self->dirty_area.y2 = y + 1;
128+
}
129+
}
130+
131+
// Update our data
107132
int32_t row_start = y * self->stride;
108133
uint32_t bytes_per_value = self->bits_per_value / 8;
109134
if (bytes_per_value < 1) {
@@ -124,3 +149,16 @@ void common_hal_displayio_bitmap_set_pixel(displayio_bitmap_t *self, int16_t x,
124149
}
125150
}
126151
}
152+
153+
displayio_area_t* displayio_bitmap_get_refresh_areas(displayio_bitmap_t *self, displayio_area_t* tail) {
154+
if (self->dirty_area.x1 == self->dirty_area.x2) {
155+
return tail;
156+
}
157+
self->dirty_area.next = tail;
158+
return &self->dirty_area;
159+
}
160+
161+
void displayio_bitmap_finish_refresh(displayio_bitmap_t *self) {
162+
self->dirty_area.x1 = 0;
163+
self->dirty_area.x2 = 0;
164+
}

shared-module/displayio/Bitmap.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <stdint.h>
3232

3333
#include "py/obj.h"
34+
#include "shared-module/displayio/area.h"
3435

3536
typedef struct {
3637
mp_obj_base_t base;
@@ -41,8 +42,12 @@ typedef struct {
4142
uint8_t bits_per_value;
4243
uint8_t x_shift;
4344
size_t x_mask;
45+
displayio_area_t dirty_area;
4446
uint16_t bitmask;
4547
bool read_only;
4648
} displayio_bitmap_t;
4749

50+
void displayio_bitmap_finish_refresh(displayio_bitmap_t *self);
51+
displayio_area_t* displayio_bitmap_get_refresh_areas(displayio_bitmap_t *self, displayio_area_t* tail);
52+
4853
#endif // MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_BITMAP_H

shared-module/displayio/TileGrid.c

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,15 @@
2626

2727
#include "shared-bindings/displayio/TileGrid.h"
2828

29+
#include "py/runtime.h"
2930
#include "shared-bindings/displayio/Bitmap.h"
3031
#include "shared-bindings/displayio/ColorConverter.h"
3132
#include "shared-bindings/displayio/OnDiskBitmap.h"
3233
#include "shared-bindings/displayio/Palette.h"
3334
#include "shared-bindings/displayio/Shape.h"
3435

3536
void common_hal_displayio_tilegrid_construct(displayio_tilegrid_t *self, mp_obj_t bitmap,
36-
uint16_t bitmap_width_in_tiles,
37+
uint16_t bitmap_width_in_tiles, uint16_t bitmap_height_in_tiles,
3738
mp_obj_t pixel_shader, uint16_t width, uint16_t height,
3839
uint16_t tile_width, uint16_t tile_height, uint16_t x, uint16_t y, uint8_t default_tile) {
3940
uint32_t total_tiles = width * height;
@@ -54,6 +55,7 @@ void common_hal_displayio_tilegrid_construct(displayio_tilegrid_t *self, mp_obj_
5455
self->inline_tiles = false;
5556
}
5657
self->bitmap_width_in_tiles = bitmap_width_in_tiles;
58+
self->tiles_in_bitmap = bitmap_width_in_tiles * bitmap_height_in_tiles;
5759
self->width_in_tiles = width;
5860
self->height_in_tiles = height;
5961
self->x = x;
@@ -204,6 +206,9 @@ uint8_t common_hal_displayio_tilegrid_get_tile(displayio_tilegrid_t *self, uint1
204206
}
205207

206208
void common_hal_displayio_tilegrid_set_tile(displayio_tilegrid_t *self, uint16_t x, uint16_t y, uint8_t tile_index) {
209+
if (tile_index >= self->tiles_in_bitmap) {
210+
mp_raise_ValueError(translate("Tile value out of bounds"));
211+
}
207212
uint8_t* tiles = self->tiles;
208213
if (self->inline_tiles) {
209214
tiles = (uint8_t*) &self->tiles;
@@ -442,6 +447,14 @@ void displayio_tilegrid_finish_refresh(displayio_tilegrid_t *self) {
442447
} else if (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_colorconverter_type)) {
443448
displayio_colorconverter_finish_refresh(self->pixel_shader);
444449
}
450+
if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_bitmap_type)) {
451+
displayio_bitmap_finish_refresh(self->bitmap);
452+
} else if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_shape_type)) {
453+
// TODO: Support shape changes.
454+
} else if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_ondiskbitmap_type)) {
455+
// OnDiskBitmap changes will trigger a complete reload so no need to
456+
// track changes.
457+
}
445458
// TODO(tannewt): We could double buffer changes to position and move them over here.
446459
// That way they won't change during a refresh and tear.
447460
}
@@ -458,8 +471,21 @@ displayio_area_t* displayio_tilegrid_get_refresh_areas(displayio_tilegrid_t *sel
458471
return &self->current_area;
459472
}
460473

461-
// We must recheck if our sources require a refresh because needs_refresh may or may not have
462-
// been called.
474+
// If we have an in-memory bitmap, then check it for modifications.
475+
if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_bitmap_type)) {
476+
displayio_area_t* refresh_area = displayio_bitmap_get_refresh_areas(self->bitmap, tail);
477+
if (refresh_area != tail) {
478+
// Special case a TileGrid that shows a full bitmap and use it's
479+
// dirty area. Copy it to ours so we can transform it.
480+
if (self->tiles_in_bitmap == 1) {
481+
displayio_area_copy(refresh_area, &self->dirty_area);
482+
self->partial_change = true;
483+
} else {
484+
self->full_change = true;
485+
}
486+
}
487+
}
488+
463489
self->full_change = self->full_change ||
464490
(MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_palette_type) &&
465491
displayio_palette_needs_refresh(self->pixel_shader)) ||

shared-module/displayio/TileGrid.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ typedef struct {
4141
int16_t y;
4242
uint16_t pixel_width;
4343
uint16_t pixel_height;
44-
uint16_t bitmap_width_in_tiles;
44+
uint16_t bitmap_width_in_tiles;;
45+
uint8_t tiles_in_bitmap;
4546
uint16_t width_in_tiles;
4647
uint16_t height_in_tiles;
4748
uint16_t tile_width;

supervisor/shared/display.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,10 @@
3535
// These are autogenerated resources.
3636

3737
// This is fixed so it doesn't need to be in RAM.
38-
extern const displayio_bitmap_t supervisor_terminal_font_bitmap;
39-
4038
extern const fontio_builtinfont_t supervisor_terminal_font;
4139

4240
// These will change so they must live in RAM.
41+
extern displayio_bitmap_t supervisor_terminal_font_bitmap;
4342
extern displayio_tilegrid_t supervisor_terminal_text_grid;
4443
extern terminalio_terminal_obj_t supervisor_terminal;
4544

tools/gen_display_resources.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ def _load_row(self, y, row):
122122
.pixel_width = {1},
123123
.pixel_height = {2},
124124
.bitmap_width_in_tiles = {0},
125+
.tiles_in_bitmap = {0},
125126
.width_in_tiles = 1,
126127
.height_in_tiles = 1,
127128
.tile_width = {1},
@@ -150,7 +151,7 @@ def _load_row(self, y, row):
150151
""")
151152

152153
c_file.write("""\
153-
const displayio_bitmap_t supervisor_terminal_font_bitmap = {{
154+
displayio_bitmap_t supervisor_terminal_font_bitmap = {{
154155
.base = {{.type = &displayio_bitmap_type }},
155156
.width = {},
156157
.height = {},

0 commit comments

Comments
 (0)
0