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
This commit is contained in:
parent
d12e1a8d74
commit
4a6bdb6fe4
@ -131,7 +131,8 @@ STATIC mp_obj_t displayio_tilegrid_make_new(const mp_obj_type_t *type, size_t n_
|
||||
|
||||
displayio_tilegrid_t *self = m_new_obj(displayio_tilegrid_t);
|
||||
self->base.type = &displayio_tilegrid_type;
|
||||
common_hal_displayio_tilegrid_construct(self, native, bitmap_width / tile_width,
|
||||
common_hal_displayio_tilegrid_construct(self, native,
|
||||
bitmap_width / tile_width, bitmap_height / tile_height,
|
||||
pixel_shader, args[ARG_width].u_int, args[ARG_height].u_int,
|
||||
tile_width, tile_height, x, y, args[ARG_default_tile].u_int);
|
||||
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
|
||||
}
|
||||
if (x >= common_hal_displayio_tilegrid_get_width(self) ||
|
||||
y >= common_hal_displayio_tilegrid_get_height(self)) {
|
||||
mp_raise_IndexError(translate("tile index out of bounds"));
|
||||
mp_raise_IndexError(translate("Tile index out of bounds"));
|
||||
}
|
||||
|
||||
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
|
||||
} else {
|
||||
mp_int_t value = mp_obj_get_int(value_obj);
|
||||
if (value < 0 || value > 255) {
|
||||
mp_raise_ValueError(translate("Tile indices must be 0 - 255"));
|
||||
mp_raise_ValueError(translate("Tile value out of bounds"));
|
||||
}
|
||||
common_hal_displayio_tilegrid_set_tile(self, x, y, value);
|
||||
}
|
||||
|
@ -32,7 +32,8 @@
|
||||
extern const mp_obj_type_t displayio_tilegrid_type;
|
||||
|
||||
void common_hal_displayio_tilegrid_construct(displayio_tilegrid_t *self, mp_obj_t bitmap,
|
||||
uint16_t bitmap_width_in_tiles, mp_obj_t pixel_shader, uint16_t width, uint16_t height,
|
||||
uint16_t bitmap_width_in_tiles, uint16_t bitmap_height_in_tiles,
|
||||
mp_obj_t pixel_shader, uint16_t width, uint16_t height,
|
||||
uint16_t tile_width, uint16_t tile_height, uint16_t x, uint16_t y, uint8_t default_tile);
|
||||
|
||||
mp_int_t common_hal_displayio_tilegrid_get_x(displayio_tilegrid_t *self);
|
||||
|
@ -63,6 +63,11 @@ void common_hal_displayio_bitmap_construct(displayio_bitmap_t *self, uint32_t wi
|
||||
}
|
||||
self->x_mask = (1 << self->x_shift) - 1; // Used as a modulus on the x value
|
||||
self->bitmask = (1 << bits_per_value) - 1;
|
||||
|
||||
self->dirty_area.x1 = 0;
|
||||
self->dirty_area.x2 = width;
|
||||
self->dirty_area.y1 = 0;
|
||||
self->dirty_area.y2 = height;
|
||||
}
|
||||
|
||||
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,
|
||||
if (self->read_only) {
|
||||
mp_raise_RuntimeError(translate("Read-only object"));
|
||||
}
|
||||
// Update the dirty area.
|
||||
if (self->dirty_area.x1 == self->dirty_area.x2) {
|
||||
self->dirty_area.x1 = x;
|
||||
self->dirty_area.x2 = x + 1;
|
||||
self->dirty_area.y1 = y;
|
||||
self->dirty_area.y2 = y + 1;
|
||||
} else {
|
||||
if (x < self->dirty_area.x1) {
|
||||
self->dirty_area.x1 = x;
|
||||
} else if (x >= self->dirty_area.x2) {
|
||||
self->dirty_area.x2 = x + 1;
|
||||
}
|
||||
if (y < self->dirty_area.y1) {
|
||||
self->dirty_area.y1 = y;
|
||||
} else if (y >= self->dirty_area.y2) {
|
||||
self->dirty_area.y2 = y + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Update our data
|
||||
int32_t row_start = y * self->stride;
|
||||
uint32_t bytes_per_value = self->bits_per_value / 8;
|
||||
if (bytes_per_value < 1) {
|
||||
@ -124,3 +149,16 @@ void common_hal_displayio_bitmap_set_pixel(displayio_bitmap_t *self, int16_t x,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
displayio_area_t* displayio_bitmap_get_refresh_areas(displayio_bitmap_t *self, displayio_area_t* tail) {
|
||||
if (self->dirty_area.x1 == self->dirty_area.x2) {
|
||||
return tail;
|
||||
}
|
||||
self->dirty_area.next = tail;
|
||||
return &self->dirty_area;
|
||||
}
|
||||
|
||||
void displayio_bitmap_finish_refresh(displayio_bitmap_t *self) {
|
||||
self->dirty_area.x1 = 0;
|
||||
self->dirty_area.x2 = 0;
|
||||
}
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "shared-module/displayio/area.h"
|
||||
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
@ -41,8 +42,12 @@ typedef struct {
|
||||
uint8_t bits_per_value;
|
||||
uint8_t x_shift;
|
||||
size_t x_mask;
|
||||
displayio_area_t dirty_area;
|
||||
uint16_t bitmask;
|
||||
bool read_only;
|
||||
} displayio_bitmap_t;
|
||||
|
||||
void displayio_bitmap_finish_refresh(displayio_bitmap_t *self);
|
||||
displayio_area_t* displayio_bitmap_get_refresh_areas(displayio_bitmap_t *self, displayio_area_t* tail);
|
||||
|
||||
#endif // MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_BITMAP_H
|
||||
|
@ -26,6 +26,7 @@
|
||||
|
||||
#include "shared-bindings/displayio/TileGrid.h"
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "shared-bindings/displayio/Bitmap.h"
|
||||
#include "shared-bindings/displayio/ColorConverter.h"
|
||||
#include "shared-bindings/displayio/OnDiskBitmap.h"
|
||||
@ -33,7 +34,7 @@
|
||||
#include "shared-bindings/displayio/Shape.h"
|
||||
|
||||
void common_hal_displayio_tilegrid_construct(displayio_tilegrid_t *self, mp_obj_t bitmap,
|
||||
uint16_t bitmap_width_in_tiles,
|
||||
uint16_t bitmap_width_in_tiles, uint16_t bitmap_height_in_tiles,
|
||||
mp_obj_t pixel_shader, uint16_t width, uint16_t height,
|
||||
uint16_t tile_width, uint16_t tile_height, uint16_t x, uint16_t y, uint8_t default_tile) {
|
||||
uint32_t total_tiles = width * height;
|
||||
@ -54,6 +55,7 @@ void common_hal_displayio_tilegrid_construct(displayio_tilegrid_t *self, mp_obj_
|
||||
self->inline_tiles = false;
|
||||
}
|
||||
self->bitmap_width_in_tiles = bitmap_width_in_tiles;
|
||||
self->tiles_in_bitmap = bitmap_width_in_tiles * bitmap_height_in_tiles;
|
||||
self->width_in_tiles = width;
|
||||
self->height_in_tiles = height;
|
||||
self->x = x;
|
||||
@ -204,6 +206,9 @@ uint8_t common_hal_displayio_tilegrid_get_tile(displayio_tilegrid_t *self, uint1
|
||||
}
|
||||
|
||||
void common_hal_displayio_tilegrid_set_tile(displayio_tilegrid_t *self, uint16_t x, uint16_t y, uint8_t tile_index) {
|
||||
if (tile_index >= self->tiles_in_bitmap) {
|
||||
mp_raise_ValueError(translate("Tile value out of bounds"));
|
||||
}
|
||||
uint8_t* tiles = self->tiles;
|
||||
if (self->inline_tiles) {
|
||||
tiles = (uint8_t*) &self->tiles;
|
||||
@ -442,6 +447,14 @@ void displayio_tilegrid_finish_refresh(displayio_tilegrid_t *self) {
|
||||
} else if (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_colorconverter_type)) {
|
||||
displayio_colorconverter_finish_refresh(self->pixel_shader);
|
||||
}
|
||||
if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_bitmap_type)) {
|
||||
displayio_bitmap_finish_refresh(self->bitmap);
|
||||
} else if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_shape_type)) {
|
||||
// TODO: Support shape changes.
|
||||
} else if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_ondiskbitmap_type)) {
|
||||
// OnDiskBitmap changes will trigger a complete reload so no need to
|
||||
// track changes.
|
||||
}
|
||||
// TODO(tannewt): We could double buffer changes to position and move them over here.
|
||||
// That way they won't change during a refresh and tear.
|
||||
}
|
||||
@ -458,8 +471,21 @@ displayio_area_t* displayio_tilegrid_get_refresh_areas(displayio_tilegrid_t *sel
|
||||
return &self->current_area;
|
||||
}
|
||||
|
||||
// We must recheck if our sources require a refresh because needs_refresh may or may not have
|
||||
// been called.
|
||||
// If we have an in-memory bitmap, then check it for modifications.
|
||||
if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_bitmap_type)) {
|
||||
displayio_area_t* refresh_area = displayio_bitmap_get_refresh_areas(self->bitmap, tail);
|
||||
if (refresh_area != tail) {
|
||||
// Special case a TileGrid that shows a full bitmap and use it's
|
||||
// dirty area. Copy it to ours so we can transform it.
|
||||
if (self->tiles_in_bitmap == 1) {
|
||||
displayio_area_copy(refresh_area, &self->dirty_area);
|
||||
self->partial_change = true;
|
||||
} else {
|
||||
self->full_change = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self->full_change = self->full_change ||
|
||||
(MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_palette_type) &&
|
||||
displayio_palette_needs_refresh(self->pixel_shader)) ||
|
||||
|
@ -41,7 +41,8 @@ typedef struct {
|
||||
int16_t y;
|
||||
uint16_t pixel_width;
|
||||
uint16_t pixel_height;
|
||||
uint16_t bitmap_width_in_tiles;
|
||||
uint16_t bitmap_width_in_tiles;;
|
||||
uint8_t tiles_in_bitmap;
|
||||
uint16_t width_in_tiles;
|
||||
uint16_t height_in_tiles;
|
||||
uint16_t tile_width;
|
||||
|
@ -35,11 +35,10 @@
|
||||
// These are autogenerated resources.
|
||||
|
||||
// This is fixed so it doesn't need to be in RAM.
|
||||
extern const displayio_bitmap_t supervisor_terminal_font_bitmap;
|
||||
|
||||
extern const fontio_builtinfont_t supervisor_terminal_font;
|
||||
|
||||
// These will change so they must live in RAM.
|
||||
extern displayio_bitmap_t supervisor_terminal_font_bitmap;
|
||||
extern displayio_tilegrid_t supervisor_terminal_text_grid;
|
||||
extern terminalio_terminal_obj_t supervisor_terminal;
|
||||
|
||||
|
@ -122,6 +122,7 @@ displayio_tilegrid_t supervisor_terminal_text_grid = {{
|
||||
.pixel_width = {1},
|
||||
.pixel_height = {2},
|
||||
.bitmap_width_in_tiles = {0},
|
||||
.tiles_in_bitmap = {0},
|
||||
.width_in_tiles = 1,
|
||||
.height_in_tiles = 1,
|
||||
.tile_width = {1},
|
||||
@ -150,7 +151,7 @@ c_file.write("""\
|
||||
""")
|
||||
|
||||
c_file.write("""\
|
||||
const displayio_bitmap_t supervisor_terminal_font_bitmap = {{
|
||||
displayio_bitmap_t supervisor_terminal_font_bitmap = {{
|
||||
.base = {{.type = &displayio_bitmap_type }},
|
||||
.width = {},
|
||||
.height = {},
|
||||
|
Loading…
Reference in New Issue
Block a user