diff --git a/docs/library/framebuf.rst b/docs/library/framebuf.rst index e2a231207d673..dfed26b042e43 100644 --- a/docs/library/framebuf.rst +++ b/docs/library/framebuf.rst @@ -192,7 +192,20 @@ Constants .. data:: framebuf.RGB565 - Red Green Blue (16-bit, 5+6+5) color format + Red Green Blue (16-bit, 5+6+5, native) color format in native byte-order. + +.. data:: framebuf.RGB565_LE + + Red Green Blue (16-bit, 5+6+5, little-endian) color format in little-endian + byte order. This defines a 16-bit format where the bytes are stored in + little-endian order. If the system is little-endian, this is the same as + ``RGB565``. + +.. data:: framebuf.RGB565_BE + + Red Green Blue (16-bit, 5+6+5, big-endian) color format in big-endian byte + order. This defines a 16-bit format where the bytes are stored in + big-endian order. If the system is big-endian, this is the same as ``RGB565``. .. data:: framebuf.GS2_HMSB diff --git a/examples/natmod/framebuf/framebuf.c b/examples/natmod/framebuf/framebuf.c index 5fd7c6be3a456..e05799d1eb389 100644 --- a/examples/natmod/framebuf/framebuf.c +++ b/examples/natmod/framebuf/framebuf.c @@ -44,6 +44,13 @@ mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *a mp_store_global(MP_QSTR_MVLSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MVLSB)); mp_store_global(MP_QSTR_MONO_VLSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MVLSB)); mp_store_global(MP_QSTR_RGB565, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_RGB565)); + #if MP_ENDIANNESS_LITTLE + mp_store_global(MP_QSTR_RGB565_LE, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_RGB565)); + mp_store_global(MP_QSTR_RGB565_BE, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_RGB565_BS)); + #else + mp_store_global(MP_QSTR_RGB565_BE, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_RGB565)); + mp_store_global(MP_QSTR_RGB565_LE, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_RGB565_BS)); + #endif mp_store_global(MP_QSTR_GS2_HMSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_GS2_HMSB)); mp_store_global(MP_QSTR_GS4_HMSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_GS4_HMSB)); mp_store_global(MP_QSTR_GS8, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_GS8)); diff --git a/extmod/modframebuf.c b/extmod/modframebuf.c index 593125aa16f91..be80000c3550f 100644 --- a/extmod/modframebuf.c +++ b/extmod/modframebuf.c @@ -57,13 +57,14 @@ typedef struct _mp_framebuf_p_t { } mp_framebuf_p_t; // constants for formats -#define FRAMEBUF_MVLSB (0) -#define FRAMEBUF_RGB565 (1) -#define FRAMEBUF_GS2_HMSB (5) -#define FRAMEBUF_GS4_HMSB (2) -#define FRAMEBUF_GS8 (6) -#define FRAMEBUF_MHLSB (3) -#define FRAMEBUF_MHMSB (4) +#define FRAMEBUF_MVLSB (0) +#define FRAMEBUF_RGB565 (1) +#define FRAMEBUF_RGB565_BS (7) +#define FRAMEBUF_GS2_HMSB (5) +#define FRAMEBUF_GS4_HMSB (2) +#define FRAMEBUF_GS8 (6) +#define FRAMEBUF_MHLSB (3) +#define FRAMEBUF_MHMSB (4) // Functions for MHLSB and MHMSB @@ -117,7 +118,10 @@ static void mvlsb_fill_rect(const mp_obj_framebuf_t *fb, unsigned int x, unsigne } } -// Functions for RGB565 format +// Functions for RGB565 and RGB565_BS format +// +// Internally we use 'native' and 'byte-swapped' formats, and then expose those as big- or little- +// endian to Python as appropriate. static void rgb565_setpixel(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y, uint32_t col) { ((uint16_t *)fb->buf)[x + y * fb->stride] = col; @@ -127,7 +131,20 @@ static uint32_t rgb565_getpixel(const mp_obj_framebuf_t *fb, unsigned int x, uns return ((uint16_t *)fb->buf)[x + y * fb->stride]; } +static void rgb565_bs_setpixel(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y, uint32_t col) { + col = __builtin_bswap16(col); + ((uint16_t *)fb->buf)[x + y * fb->stride] = col; +} + +static uint32_t rgb565_bs_getpixel(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y) { + uint32_t col = ((uint16_t *)fb->buf)[x + y * fb->stride]; + return __builtin_bswap16(col); +} + static void rgb565_fill_rect(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y, unsigned int w, unsigned int h, uint32_t col) { + if (fb->format == FRAMEBUF_RGB565_BS) { + col = __builtin_bswap16(col); + } uint16_t *b = &((uint16_t *)fb->buf)[x + y * fb->stride]; while (h--) { for (unsigned int ww = w; ww; --ww) { @@ -234,6 +251,7 @@ static void gs8_fill_rect(const mp_obj_framebuf_t *fb, unsigned int x, unsigned static mp_framebuf_p_t formats[] = { [FRAMEBUF_MVLSB] = {mvlsb_setpixel, mvlsb_getpixel, mvlsb_fill_rect}, [FRAMEBUF_RGB565] = {rgb565_setpixel, rgb565_getpixel, rgb565_fill_rect}, + [FRAMEBUF_RGB565_BS] = {rgb565_bs_setpixel, rgb565_bs_getpixel, rgb565_fill_rect}, [FRAMEBUF_GS2_HMSB] = {gs2_hmsb_setpixel, gs2_hmsb_getpixel, gs2_hmsb_fill_rect}, [FRAMEBUF_GS4_HMSB] = {gs4_hmsb_setpixel, gs4_hmsb_getpixel, gs4_hmsb_fill_rect}, [FRAMEBUF_GS8] = {gs8_setpixel, gs8_getpixel, gs8_fill_rect}, @@ -310,6 +328,7 @@ static mp_obj_t framebuf_make_new_helper(size_t n_args, const mp_obj_t *args_in, bpp = 8; break; case FRAMEBUF_RGB565: + case FRAMEBUF_RGB565_BS: bpp = 16; break; default: @@ -909,6 +928,13 @@ static const mp_rom_map_elem_t framebuf_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_MVLSB), MP_ROM_INT(FRAMEBUF_MVLSB) }, { MP_ROM_QSTR(MP_QSTR_MONO_VLSB), MP_ROM_INT(FRAMEBUF_MVLSB) }, { MP_ROM_QSTR(MP_QSTR_RGB565), MP_ROM_INT(FRAMEBUF_RGB565) }, + #if MP_ENDIANNESS_LITTLE + { MP_ROM_QSTR(MP_QSTR_RGB565_LE), MP_ROM_INT(FRAMEBUF_RGB565) }, + { MP_ROM_QSTR(MP_QSTR_RGB565_BE), MP_ROM_INT(FRAMEBUF_RGB565_BS) }, + #elif MP_ENDIANNESS_BIG + { MP_ROM_QSTR(MP_QSTR_RGB565_BE), MP_ROM_INT(FRAMEBUF_RGB565) }, + { MP_ROM_QSTR(MP_QSTR_RGB565_LE), MP_ROM_INT(FRAMEBUF_RGB565_BS) }, + #endif // MP_ENDIANNESS_... { MP_ROM_QSTR(MP_QSTR_GS2_HMSB), MP_ROM_INT(FRAMEBUF_GS2_HMSB) }, { MP_ROM_QSTR(MP_QSTR_GS4_HMSB), MP_ROM_INT(FRAMEBUF_GS4_HMSB) }, { MP_ROM_QSTR(MP_QSTR_GS8), MP_ROM_INT(FRAMEBUF_GS8) }, diff --git a/tests/extmod/framebuf16.py b/tests/extmod/framebuf16.py index 9f373c331e51f..7d4c21ff9ada3 100644 --- a/tests/extmod/framebuf16.py +++ b/tests/extmod/framebuf16.py @@ -4,10 +4,12 @@ print("SKIP") raise SystemExit -# This test and its .exp file is based on a little-endian architecture. -if sys.byteorder != "little": - print("SKIP") - raise SystemExit +if (sys.byteorder == "little" and framebuf.RGB565 == framebuf.RGB565_LE) or ( + sys.byteorder == "big" and framebuf.RGB565 == framebuf.RGB565_BE +): + print("Native format matches expected value.") +else: + print("Unexpected native format.") def printbuf(): @@ -17,50 +19,51 @@ def printbuf(): print("-->8--") -w = 4 -h = 5 -buf = bytearray(w * h * 2) -fbuf = framebuf.FrameBuffer(buf, w, h, framebuf.RGB565) +for format in [framebuf.RGB565_LE, framebuf.RGB565_BE]: + w = 4 + h = 5 + buf = bytearray(w * h * 2) + fbuf = framebuf.FrameBuffer(buf, w, h, format) -# fill -fbuf.fill(0xFFFF) -printbuf() -fbuf.fill(0x0000) -printbuf() + # fill + fbuf.fill(0xFFFF) + printbuf() + fbuf.fill(0x0000) + printbuf() -# put pixel -fbuf.pixel(0, 0, 0xEEEE) -fbuf.pixel(3, 0, 0xEE00) -fbuf.pixel(0, 4, 0x00EE) -fbuf.pixel(3, 4, 0x0EE0) -printbuf() + # put pixel + fbuf.pixel(0, 0, 0xEEEE) + fbuf.pixel(3, 0, 0xEE00) + fbuf.pixel(0, 4, 0x00EE) + fbuf.pixel(3, 4, 0x0EE0) + printbuf() -# get pixel -print(fbuf.pixel(0, 4), fbuf.pixel(1, 1)) + # get pixel + print(fbuf.pixel(0, 4), fbuf.pixel(1, 1)) -# scroll -fbuf.fill(0x0000) -fbuf.pixel(2, 2, 0xFFFF) -printbuf() -fbuf.scroll(0, 1) -printbuf() -fbuf.scroll(1, 0) -printbuf() -fbuf.scroll(-1, -2) -printbuf() + # scroll + fbuf.fill(0x0000) + fbuf.pixel(2, 2, 0xFFFF) + printbuf() + fbuf.scroll(0, 1) + printbuf() + fbuf.scroll(1, 0) + printbuf() + fbuf.scroll(-1, -2) + printbuf() -w2 = 2 -h2 = 3 -buf2 = bytearray(w2 * h2 * 2) -fbuf2 = framebuf.FrameBuffer(buf2, w2, h2, framebuf.RGB565) + w2 = 2 + h2 = 3 + buf2 = bytearray(w2 * h2 * 2) + fbuf2 = framebuf.FrameBuffer(buf2, w2, h2, format) -fbuf2.fill(0x0000) -fbuf2.pixel(0, 0, 0x0EE0) -fbuf2.pixel(0, 2, 0xEE00) -fbuf2.pixel(1, 0, 0x00EE) -fbuf2.pixel(1, 2, 0xE00E) -fbuf.fill(0xFFFF) -fbuf.blit(fbuf2, 3, 3, 0x0000) -fbuf.blit(fbuf2, -1, -1, 0x0000) -fbuf.blit(fbuf2, 16, 16, 0x0000) -printbuf() + fbuf2.fill(0x0000) + fbuf2.pixel(0, 0, 0x0EE0) + fbuf2.pixel(0, 2, 0xEE00) + fbuf2.pixel(1, 0, 0x00EE) + fbuf2.pixel(1, 2, 0xE00E) + fbuf.fill(0xFFFF) + fbuf.blit(fbuf2, 3, 3, 0x0000) + fbuf.blit(fbuf2, -1, -1, 0x0000) + fbuf.blit(fbuf2, 16, 16, 0x0000) + printbuf() diff --git a/tests/extmod/framebuf16.py.exp b/tests/extmod/framebuf16.py.exp index c41dc19d07140..bb23762efcf75 100644 --- a/tests/extmod/framebuf16.py.exp +++ b/tests/extmod/framebuf16.py.exp @@ -1,3 +1,4 @@ +Native format matches expected value. --8<-- bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') @@ -55,3 +56,60 @@ bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') bytearray(b'\xff\xff\xff\xff\xff\xff\xe0\x0e') bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') -->8-- +--8<-- +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') +-->8-- +--8<-- +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +-->8-- +--8<-- +bytearray(b'\xee\xee\x00\x00\x00\x00\xee\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\xee\x00\x00\x00\x00\x0e\xe0') +-->8-- +238 0 +--8<-- +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\xff\xff\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +-->8-- +--8<-- +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\xff\xff\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +-->8-- +--8<-- +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\xff\xff') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +-->8-- +--8<-- +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\xff\xff\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\xff\xff') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +-->8-- +--8<-- +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') +bytearray(b'\xe0\x0e\xff\xff\xff\xff\xff\xff') +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') +bytearray(b'\xff\xff\xff\xff\xff\xff\x0e\xe0') +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') +-->8--