Skip to content

Commit 6fcda1d

Browse files
committed
Support multi-byte values with Bitmap
It also corrects the behavior of single byte values. Fixes #1744
1 parent 5b0c1c8 commit 6fcda1d

File tree

4 files changed

+39
-45
lines changed

4 files changed

+39
-45
lines changed

shared-module/displayio/Bitmap.c

Lines changed: 33 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -33,20 +33,21 @@
3333
void common_hal_displayio_bitmap_construct(displayio_bitmap_t *self, uint32_t width,
3434
uint32_t height, uint32_t bits_per_value) {
3535
uint32_t row_width = width * bits_per_value;
36-
// word align
37-
if (row_width % 32 != 0) {
38-
self->stride = (row_width / 32 + 1);
36+
// align to size_t
37+
uint8_t align_bits = 8 * sizeof(size_t);
38+
if (row_width % align_bits != 0) {
39+
self->stride = (row_width / align_bits + 1);
3940
} else {
40-
self->stride = row_width / 32;
41+
self->stride = row_width / align_bits;
4142
}
4243
self->width = width;
4344
self->height = height;
44-
self->data = m_malloc(self->stride * height * sizeof(uint32_t), false);
45+
self->data = m_malloc(self->stride * height * sizeof(size_t), false);
4546
self->read_only = false;
4647
self->bits_per_value = bits_per_value;
4748

48-
if (bits_per_value > 8) {
49-
mp_raise_NotImplementedError(translate("Only bit maps of 8 bit color or less are supported"));
49+
if (bits_per_value > 8 && bits_per_value != 16 && bits_per_value != 32) {
50+
mp_raise_NotImplementedError(translate("Invalid bits per value"));
5051
}
5152

5253
// Division and modulus can be slow because it has to handle any integer. We know bits_per_value
@@ -56,7 +57,7 @@ void common_hal_displayio_bitmap_construct(displayio_bitmap_t *self, uint32_t wi
5657
self->x_shift = 0; // Used to divide the index by the number of pixels per word. Its used in a
5758
// shift which effectively divides by 2 ** x_shift.
5859
uint32_t power_of_two = 1;
59-
while (power_of_two < 32 / bits_per_value ) {
60+
while (power_of_two < align_bits / bits_per_value ) {
6061
self->x_shift++;
6162
power_of_two <<= 1;
6263
}
@@ -76,57 +77,50 @@ uint32_t common_hal_displayio_bitmap_get_bits_per_value(displayio_bitmap_t *self
7677
return self->bits_per_value;
7778
}
7879

79-
void common_hal_displayio_bitmap_load_row(displayio_bitmap_t *self, uint16_t y, uint8_t* data, uint16_t len) {
80-
if (len != self->stride * sizeof(uint32_t)) {
81-
mp_raise_ValueError(translate("row must be packed and word aligned"));
82-
}
83-
uint32_t* row_value = self->data + (y * self->stride);
84-
// Do the memcpy ourselves since we may want to flip endianness.
85-
for (uint32_t i = 0; i < self->stride; i++) {
86-
#pragma GCC diagnostic push
87-
#pragma GCC diagnostic ignored "-Wcast-align"
88-
uint32_t value = ((uint32_t *)data)[i];
89-
#pragma GCC diagnostic pop
90-
if (self->bits_per_value < 16) {
91-
value = ((value >> 24) & 0xff) |
92-
((value << 8) & 0xff0000) |
93-
((value >> 8) & 0xff00) |
94-
((value << 24) & 0xff000000);
95-
}
96-
*row_value = value;
97-
row_value++;
98-
}
99-
}
100-
10180
uint32_t common_hal_displayio_bitmap_get_pixel(displayio_bitmap_t *self, int16_t x, int16_t y) {
10281
if (x >= self->width || x < 0 || y >= self->height || y < 0) {
10382
return 0;
10483
}
10584
int32_t row_start = y * self->stride;
106-
if (self->bits_per_value < 8) {
107-
uint32_t word = self->data[row_start + (x >> self->x_shift)];
85+
uint32_t bytes_per_value = self->bits_per_value / 8;
86+
if (bytes_per_value < 1) {
87+
size_t word = self->data[row_start + (x >> self->x_shift)];
10888

109-
return (word >> (32 - ((x & self->x_mask) + 1) * self->bits_per_value)) & self->bitmask;
89+
return (word >> (sizeof(size_t) * 8 - ((x & self->x_mask) + 1) * self->bits_per_value)) & self->bitmask;
11090
} else {
111-
uint32_t bytes_per_value = self->bits_per_value / 8;
112-
return self->data[row_start + x * bytes_per_value];
91+
size_t* row = self->data + row_start;
92+
if (bytes_per_value == 1) {
93+
return ((uint8_t*) row)[x];
94+
} else if (bytes_per_value == 2) {
95+
return ((uint16_t*) row)[x];
96+
} else if (bytes_per_value == 4) {
97+
return ((uint32_t*) row)[x];
98+
}
11399
}
100+
return 0;
114101
}
115102

116103
void common_hal_displayio_bitmap_set_pixel(displayio_bitmap_t *self, int16_t x, int16_t y, uint32_t value) {
117104
if (self->read_only) {
118105
mp_raise_RuntimeError(translate("Read-only object"));
119106
}
120107
int32_t row_start = y * self->stride;
121-
if (self->bits_per_value < 8) {
122-
uint32_t bit_position = (32 - ((x & self->x_mask) + 1) * self->bits_per_value);
108+
uint32_t bytes_per_value = self->bits_per_value / 8;
109+
if (bytes_per_value < 1) {
110+
uint32_t bit_position = (sizeof(size_t) * 8 - ((x & self->x_mask) + 1) * self->bits_per_value);
123111
uint32_t index = row_start + (x >> self->x_shift);
124112
uint32_t word = self->data[index];
125113
word &= ~(self->bitmask << bit_position);
126114
word |= (value & self->bitmask) << bit_position;
127115
self->data[index] = word;
128116
} else {
129-
uint32_t bytes_per_value = self->bits_per_value / 8;
130-
self->data[row_start + x * bytes_per_value] = value;
117+
size_t* row = self->data + row_start;
118+
if (bytes_per_value == 1) {
119+
((uint8_t*) row)[x] = value;
120+
} else if (bytes_per_value == 2) {
121+
((uint16_t*) row)[x] = value;
122+
} else if (bytes_per_value == 4) {
123+
((uint32_t*) row)[x] = value;
124+
}
131125
}
132126
}

shared-module/displayio/Bitmap.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ typedef struct {
3636
mp_obj_base_t base;
3737
uint16_t width;
3838
uint16_t height;
39-
uint32_t* data;
40-
uint16_t stride; // words
39+
size_t* data;
40+
uint16_t stride; // size_t's
4141
uint8_t bits_per_value;
4242
uint8_t x_shift;
43-
uint8_t x_mask;
43+
size_t x_mask;
4444
uint16_t bitmask;
4545
bool read_only;
4646
} displayio_bitmap_t;

supervisor/shared/display.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
#include "shared-bindings/displayio/TileGrid.h"
3535
#include "supervisor/memory.h"
3636

37-
extern uint32_t blinka_bitmap_data[];
37+
extern size_t blinka_bitmap_data[];
3838
extern displayio_bitmap_t blinka_bitmap;
3939
extern displayio_group_t circuitpython_splash;
4040

@@ -107,7 +107,7 @@ void supervisor_display_move_memory(void) {
107107
#endif
108108
}
109109

110-
uint32_t blinka_bitmap_data[32] = {
110+
size_t blinka_bitmap_data[32] = {
111111
0x00000011, 0x11000000,
112112
0x00000111, 0x53100000,
113113
0x00000111, 0x56110000,

tools/gen_display_resources.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ def _load_row(self, y, row):
153153
.base = {{.type = &displayio_bitmap_type }},
154154
.width = {},
155155
.height = {},
156-
.data = (uint32_t*) font_bitmap_data,
156+
.data = (size_t*) font_bitmap_data,
157157
.stride = {},
158158
.bits_per_value = 1,
159159
.x_shift = 5,

0 commit comments

Comments
 (0)