Skip to content

Commit 578d2eb

Browse files
committed
displayio: cache 64 bytes of an OnDiskBitmap file
get_pixel() did a seek and a read of 1-4 bytes for every pixel. The file system caches the sector, but the calls alone cost about 13 us a pixel on an RP2040. Read 64 bytes at a time and take the next pixels from them.
1 parent bccf825 commit 578d2eb

2 files changed

Lines changed: 41 additions & 32 deletions

File tree

‎shared-module/displayio/OnDiskBitmap.c‎

Lines changed: 37 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ static uint32_t read_word(uint16_t *bmp_header, uint16_t index) {
2828

2929
void common_hal_displayio_ondiskbitmap_construct(displayio_ondiskbitmap_t *self, mp_obj_t file) {
3030
self->file = file;
31+
self->cache_len = 0;
3132
uint16_t bmp_header[69];
3233
int errcode = 0;
3334

@@ -182,43 +183,47 @@ uint32_t common_hal_displayio_ondiskbitmap_get_pixel(displayio_ondiskbitmap_t *s
182183
} else {
183184
location = self->data_offset + (self->height - y - 1) * self->stride + x / pixels_per_byte;
184185
}
185-
// We don't cache here because the underlying FS caches sectors.
186186
int errcode = 0;
187-
mp_stream_seek(self->file, location, MP_SEEK_SET, &errcode);
188-
if (errcode != 0) {
189-
return 0;
187+
if (location < self->cache_start || location + bytes_per_pixel > self->cache_start + self->cache_len) {
188+
mp_stream_seek(self->file, location, MP_SEEK_SET, &errcode);
189+
if (errcode != 0) {
190+
return 0;
191+
}
192+
self->cache_start = location;
193+
self->cache_len = mp_stream_rw(self->file, self->cache, sizeof(self->cache), &errcode, MP_STREAM_RW_ONCE);
194+
if (errcode != 0 || self->cache_len < bytes_per_pixel) {
195+
self->cache_len = 0;
196+
return 0;
197+
}
190198
}
191199
uint32_t pixel_data = 0;
192-
mp_stream_rw(self->file, &pixel_data, bytes_per_pixel, &errcode, MP_STREAM_RW_ONCE);
193-
if (errcode == 0) {
194-
uint32_t tmp = 0;
195-
uint8_t red;
196-
uint8_t green;
197-
uint8_t blue;
198-
if (bytes_per_pixel == 1) {
199-
uint8_t offset = (x % pixels_per_byte) * self->bits_per_pixel;
200-
uint8_t mask = (1 << self->bits_per_pixel) - 1;
201-
202-
return (pixel_data >> ((8 - self->bits_per_pixel) - offset)) & mask;
203-
} else if (bytes_per_pixel == 2) {
204-
if (self->g_bitmask == 0x07e0) { // 565
205-
red = ((pixel_data & self->r_bitmask) >> 11);
206-
green = ((pixel_data & self->g_bitmask) >> 5);
207-
blue = ((pixel_data & self->b_bitmask) >> 0);
208-
} else { // 555
209-
red = ((pixel_data & self->r_bitmask) >> 10);
210-
green = ((pixel_data & self->g_bitmask) >> 4);
211-
blue = ((pixel_data & self->b_bitmask) >> 0);
212-
}
213-
tmp = (red << 19 | green << 10 | blue << 3);
214-
return tmp;
215-
} else if ((bytes_per_pixel == 4) && (self->bitfield_compressed)) {
216-
return pixel_data & 0x00FFFFFF;
217-
} else {
218-
return pixel_data;
200+
memcpy(&pixel_data, self->cache + (location - self->cache_start), bytes_per_pixel);
201+
uint32_t tmp = 0;
202+
uint8_t red;
203+
uint8_t green;
204+
uint8_t blue;
205+
if (bytes_per_pixel == 1) {
206+
uint8_t offset = (x % pixels_per_byte) * self->bits_per_pixel;
207+
uint8_t mask = (1 << self->bits_per_pixel) - 1;
208+
209+
return (pixel_data >> ((8 - self->bits_per_pixel) - offset)) & mask;
210+
} else if (bytes_per_pixel == 2) {
211+
if (self->g_bitmask == 0x07e0) { // 565
212+
red = ((pixel_data & self->r_bitmask) >> 11);
213+
green = ((pixel_data & self->g_bitmask) >> 5);
214+
blue = ((pixel_data & self->b_bitmask) >> 0);
215+
} else { // 555
216+
red = ((pixel_data & self->r_bitmask) >> 10);
217+
green = ((pixel_data & self->g_bitmask) >> 4);
218+
blue = ((pixel_data & self->b_bitmask) >> 0);
219219
}
220+
tmp = (red << 19 | green << 10 | blue << 3);
221+
return tmp;
222+
} else if ((bytes_per_pixel == 4) && (self->bitfield_compressed)) {
223+
return pixel_data & 0x00FFFFFF;
224+
} else {
225+
return pixel_data;
220226
}
221-
return 0;
222227
}
223228

224229
uint16_t common_hal_displayio_ondiskbitmap_get_height(displayio_ondiskbitmap_t *self) {

‎shared-module/displayio/OnDiskBitmap.h‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,8 @@ typedef struct {
2828
};
2929
bool bitfield_compressed;
3030
uint8_t bits_per_pixel;
31+
// The last bytes read from the file. Pixels are read along rows, so most reads hit it.
32+
uint8_t cache_len;
33+
uint32_t cache_start;
34+
uint8_t cache[64];
3135
} displayio_ondiskbitmap_t;

0 commit comments

Comments
 (0)