Skip to content

Commit adca341

Browse files
committed
Save code space by packing rgbw values into C union
It's more efficient passing one register-sized structure than 4 arguments or 4 pointers; working on intermediate values of 'int' size is also more efficient in code size! On raspberry pi pico w, this increased free flash space by +104 bytes. It also increased the speed of my testing animation very slightly, from 187fps to 189fps when run 'unthrottled'
1 parent 8f414eb commit adca341

File tree

2 files changed

+35
-30
lines changed

2 files changed

+35
-30
lines changed

shared-bindings/adafruit_pixelbuf/PixelBuf.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@
3131

3232
extern const mp_obj_type_t pixelbuf_pixelbuf_type;
3333

34+
typedef union {
35+
struct {
36+
uint8_t r, g, b, w;
37+
};
38+
uint32_t rgbw;
39+
} color_u;
40+
3441
void common_hal_adafruit_pixelbuf_pixelbuf_construct(pixelbuf_pixelbuf_obj_t *self, size_t n,
3542
pixelbuf_byteorder_details_t *byteorder, mp_float_t brightness, bool auto_write, uint8_t *header,
3643
size_t header_len, uint8_t *trailer, size_t trailer_len);

shared-module/adafruit_pixelbuf/PixelBuf.c

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -152,50 +152,56 @@ STATIC uint8_t _pixelbuf_get_as_uint8(mp_obj_t obj) {
152152
translate("can't convert %q to %q"), mp_obj_get_type_qstr(obj), MP_QSTR_int);
153153
}
154154

155-
STATIC void _pixelbuf_parse_color(pixelbuf_pixelbuf_obj_t *self, mp_obj_t color, uint8_t *r, uint8_t *g, uint8_t *b, uint8_t *w) {
155+
STATIC color_u _pixelbuf_parse_color(pixelbuf_pixelbuf_obj_t *self, mp_obj_t color) {
156+
color_u result;
156157
pixelbuf_byteorder_details_t *byteorder = &self->byteorder;
157158
// w is shared between white in NeoPixels and brightness in dotstars (so that DotStars can have
158159
// per-pixel brightness). Set the defaults here in case it isn't set below.
159160
if (byteorder->is_dotstar) {
160-
*w = 255;
161+
result.w = 255;
161162
} else {
162-
*w = 0;
163+
result.w = 0;
163164
}
164165

165166
if (mp_obj_is_int(color) || mp_obj_is_float(color)) {
166167
mp_int_t value = mp_obj_is_int(color) ? mp_obj_get_int_truncated(color) : (mp_int_t)mp_obj_get_float(color);
167-
*r = value >> 16 & 0xff;
168-
*g = (value >> 8) & 0xff;
169-
*b = value & 0xff;
168+
result.r = value >> 16 & 0xff;
169+
result.g = (value >> 8) & 0xff;
170+
result.b = value & 0xff;
170171
} else {
171172
mp_obj_t *items;
172173
size_t len;
173174
mp_obj_get_array(color, &len, &items);
174175
mp_arg_validate_length_range(len, 3, 4, MP_QSTR_color);
175176

176-
*r = _pixelbuf_get_as_uint8(items[PIXEL_R]);
177-
*g = _pixelbuf_get_as_uint8(items[PIXEL_G]);
178-
*b = _pixelbuf_get_as_uint8(items[PIXEL_B]);
177+
result.r = _pixelbuf_get_as_uint8(items[PIXEL_R]);
178+
result.g = _pixelbuf_get_as_uint8(items[PIXEL_G]);
179+
result.b = _pixelbuf_get_as_uint8(items[PIXEL_B]);
179180
if (len > 3) {
180181
if (mp_obj_is_float(items[PIXEL_W])) {
181-
*w = 255 * mp_obj_get_float(items[PIXEL_W]);
182+
result.w = 255 * mp_obj_get_float(items[PIXEL_W]);
182183
} else {
183-
*w = mp_obj_get_int_truncated(items[PIXEL_W]);
184+
result.w = mp_obj_get_int_truncated(items[PIXEL_W]);
184185
}
185-
return;
186+
return result;
186187
}
187188
}
188189
// Int colors can't set white directly so convert to white when all components are equal.
189190
// Also handles RGBW values assigned an RGB tuple.
190-
if (!byteorder->is_dotstar && byteorder->bpp == 4 && byteorder->has_white && *r == *g && *r == *b) {
191-
*w = *r;
192-
*r = 0;
193-
*g = 0;
194-
*b = 0;
191+
if (!byteorder->is_dotstar && byteorder->bpp == 4 && byteorder->has_white && result.r == result.g && result.r == result.b) {
192+
result.w = result.r;
193+
result.r = 0;
194+
result.g = 0;
195+
result.b = 0;
195196
}
197+
return result;
196198
}
197199

198-
STATIC void _pixelbuf_set_pixel_color(pixelbuf_pixelbuf_obj_t *self, size_t index, uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
200+
STATIC void _pixelbuf_set_pixel_color(pixelbuf_pixelbuf_obj_t *self, size_t index, color_u rgbw) {
201+
int r = rgbw.r;
202+
int g = rgbw.g;
203+
int b = rgbw.b;
204+
int w = rgbw.w;
199205
// DotStars don't have white, instead they have 5 bit brightness so pack it into w. Shift right
200206
// by three to leave the top five bits.
201207
if (self->bytes_per_pixel == 4 && self->byteorder.is_dotstar) {
@@ -234,12 +240,8 @@ STATIC void _pixelbuf_set_pixel_color(pixelbuf_pixelbuf_obj_t *self, size_t inde
234240
}
235241

236242
STATIC void _pixelbuf_set_pixel(pixelbuf_pixelbuf_obj_t *self, size_t index, mp_obj_t value) {
237-
uint8_t r;
238-
uint8_t g;
239-
uint8_t b;
240-
uint8_t w;
241-
_pixelbuf_parse_color(self, value, &r, &g, &b, &w);
242-
_pixelbuf_set_pixel_color(self, index, r, g, b, w);
243+
color_u rgbw = _pixelbuf_parse_color(self, value);
244+
_pixelbuf_set_pixel_color(self, index, rgbw);
243245
}
244246

245247
void common_hal_adafruit_pixelbuf_pixelbuf_set_pixels(mp_obj_t self_in, size_t start, mp_int_t step, size_t slice_len, mp_obj_t *values,
@@ -318,14 +320,10 @@ void common_hal_adafruit_pixelbuf_pixelbuf_show(mp_obj_t self_in) {
318320
void common_hal_adafruit_pixelbuf_pixelbuf_fill(mp_obj_t self_in, mp_obj_t fill_color) {
319321
pixelbuf_pixelbuf_obj_t *self = native_pixelbuf(self_in);
320322

321-
uint8_t r;
322-
uint8_t g;
323-
uint8_t b;
324-
uint8_t w;
325-
_pixelbuf_parse_color(self, fill_color, &r, &g, &b, &w);
323+
color_u rgbw = _pixelbuf_parse_color(self, fill_color);
326324

327325
for (size_t i = 0; i < self->pixel_count; i++) {
328-
_pixelbuf_set_pixel_color(self, i, r, g, b, w);
326+
_pixelbuf_set_pixel_color(self, i, rgbw);
329327
}
330328
if (self->auto_write) {
331329
common_hal_adafruit_pixelbuf_pixelbuf_show(self_in);

0 commit comments

Comments
 (0)