Skip to content

Save code space by packing rgbw values into C union #7209

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Nov 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions shared-bindings/adafruit_pixelbuf/PixelBuf.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@

extern const mp_obj_type_t pixelbuf_pixelbuf_type;

typedef union {
struct {
uint8_t r, g, b, w;
};
uint32_t rgbw;
} color_u;

void common_hal_adafruit_pixelbuf_pixelbuf_construct(pixelbuf_pixelbuf_obj_t *self, size_t n,
pixelbuf_byteorder_details_t *byteorder, mp_float_t brightness, bool auto_write, uint8_t *header,
size_t header_len, uint8_t *trailer, size_t trailer_len);
Expand Down
60 changes: 30 additions & 30 deletions shared-module/adafruit_pixelbuf/PixelBuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,59 +143,67 @@ void common_hal_adafruit_pixelbuf_pixelbuf_set_brightness(mp_obj_t self_in, mp_f
STATIC uint8_t _pixelbuf_get_as_uint8(mp_obj_t obj) {
if (mp_obj_is_small_int(obj)) {
return MP_OBJ_SMALL_INT_VALUE(obj);
#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
} else if (mp_obj_is_int(obj)) {
return mp_obj_get_int_truncated(obj);
#endif
} else if (mp_obj_is_float(obj)) {
return (uint8_t)mp_obj_get_float(obj);
}
mp_raise_TypeError_varg(
translate("can't convert %q to %q"), mp_obj_get_type_qstr(obj), MP_QSTR_int);
}

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) {
STATIC color_u _pixelbuf_parse_color(pixelbuf_pixelbuf_obj_t *self, mp_obj_t color) {
color_u result;
pixelbuf_byteorder_details_t *byteorder = &self->byteorder;
// w is shared between white in NeoPixels and brightness in dotstars (so that DotStars can have
// per-pixel brightness). Set the defaults here in case it isn't set below.
if (byteorder->is_dotstar) {
*w = 255;
result.w = 255;
} else {
*w = 0;
result.w = 0;
}

if (mp_obj_is_int(color) || mp_obj_is_float(color)) {
mp_int_t value = mp_obj_is_int(color) ? mp_obj_get_int_truncated(color) : (mp_int_t)mp_obj_get_float(color);
*r = value >> 16 & 0xff;
*g = (value >> 8) & 0xff;
*b = value & 0xff;
result.r = value >> 16 & 0xff;
result.g = (value >> 8) & 0xff;
result.b = value & 0xff;
} else {
mp_obj_t *items;
size_t len;
mp_obj_get_array(color, &len, &items);
mp_arg_validate_length_range(len, 3, 4, MP_QSTR_color);

*r = _pixelbuf_get_as_uint8(items[PIXEL_R]);
*g = _pixelbuf_get_as_uint8(items[PIXEL_G]);
*b = _pixelbuf_get_as_uint8(items[PIXEL_B]);
result.r = _pixelbuf_get_as_uint8(items[PIXEL_R]);
result.g = _pixelbuf_get_as_uint8(items[PIXEL_G]);
result.b = _pixelbuf_get_as_uint8(items[PIXEL_B]);
if (len > 3) {
if (mp_obj_is_float(items[PIXEL_W])) {
*w = 255 * mp_obj_get_float(items[PIXEL_W]);
result.w = 255 * mp_obj_get_float(items[PIXEL_W]);
} else {
*w = mp_obj_get_int_truncated(items[PIXEL_W]);
result.w = mp_obj_get_int_truncated(items[PIXEL_W]);
}
return;
return result;
}
}
// Int colors can't set white directly so convert to white when all components are equal.
// Also handles RGBW values assigned an RGB tuple.
if (!byteorder->is_dotstar && byteorder->bpp == 4 && byteorder->has_white && *r == *g && *r == *b) {
*w = *r;
*r = 0;
*g = 0;
*b = 0;
if (!byteorder->is_dotstar && byteorder->bpp == 4 && byteorder->has_white && result.r == result.g && result.r == result.b) {
result.w = result.r;
result.r = 0;
result.g = 0;
result.b = 0;
}
return result;
}

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) {
STATIC void _pixelbuf_set_pixel_color(pixelbuf_pixelbuf_obj_t *self, size_t index, color_u rgbw) {
uint8_t r = rgbw.r;
uint8_t g = rgbw.g;
uint8_t b = rgbw.b;
uint8_t w = rgbw.w;
// DotStars don't have white, instead they have 5 bit brightness so pack it into w. Shift right
// by three to leave the top five bits.
if (self->bytes_per_pixel == 4 && self->byteorder.is_dotstar) {
Expand Down Expand Up @@ -234,12 +242,8 @@ STATIC void _pixelbuf_set_pixel_color(pixelbuf_pixelbuf_obj_t *self, size_t inde
}

STATIC void _pixelbuf_set_pixel(pixelbuf_pixelbuf_obj_t *self, size_t index, mp_obj_t value) {
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t w;
_pixelbuf_parse_color(self, value, &r, &g, &b, &w);
_pixelbuf_set_pixel_color(self, index, r, g, b, w);
color_u rgbw = _pixelbuf_parse_color(self, value);
_pixelbuf_set_pixel_color(self, index, rgbw);
}

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,
Expand Down Expand Up @@ -318,14 +322,10 @@ void common_hal_adafruit_pixelbuf_pixelbuf_show(mp_obj_t self_in) {
void common_hal_adafruit_pixelbuf_pixelbuf_fill(mp_obj_t self_in, mp_obj_t fill_color) {
pixelbuf_pixelbuf_obj_t *self = native_pixelbuf(self_in);

uint8_t r;
uint8_t g;
uint8_t b;
uint8_t w;
_pixelbuf_parse_color(self, fill_color, &r, &g, &b, &w);
color_u rgbw = _pixelbuf_parse_color(self, fill_color);

for (size_t i = 0; i < self->pixel_count; i++) {
_pixelbuf_set_pixel_color(self, i, r, g, b, w);
_pixelbuf_set_pixel_color(self, i, rgbw);
}
if (self->auto_write) {
common_hal_adafruit_pixelbuf_pixelbuf_show(self_in);
Expand Down