Skip to content

Endianness handling for RGB565 framebuf mode. #3536

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

Closed
wants to merge 1 commit into from
Closed
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
13 changes: 12 additions & 1 deletion docs/library/framebuf.rst
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,18 @@ Constants

.. data:: framebuf.RGB565

Red Green Blue (16-bit, 5+6+5) color format
Red Green Blue (16-bit, 5+6+5) device-endian color format
This will default to the device's native endianness (likely to be little-endian).

.. data:: framebuf.RGB565_BE

Red Green Blue (16-bit, 5+6+5) big-endian color format
This will result in a pixel color value of `0xabcd` being stored in the buffer as `[0xab, 0xcd]`.

.. data:: framebuf.RGB565_LE

Red Green Blue (16-bit, 5+6+5) little-endian color format
This will result in a pixel color value of `0xabcd` being stored in the buffer as `[0xcd, 0xab]`.

.. data:: framebuf.GS2_HMSB

Expand Down
55 changes: 43 additions & 12 deletions extmod/modframebuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <stdio.h>
#include <string.h>

#include "py/binary.h"
#include "py/runtime.h"

#if MICROPY_PY_FRAMEBUF
Expand All @@ -52,13 +53,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_BE (1)
#define FRAMEBUF_RGB565_LE (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

Expand Down Expand Up @@ -114,16 +116,27 @@ STATIC void mvlsb_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, in

// Functions for RGB565 format

STATIC void rgb565_flip_endian(uint32_t* col, uint8_t format) {
if ((MP_ENDIANNESS_LITTLE && format == FRAMEBUF_RGB565_BE) || (MP_ENDIANNESS_BIG && format == FRAMEBUF_RGB565_LE)) {
*col = ((*col & 0xff) << 8) | ((*col >> 8) & 0xff);
}
}

STATIC void rgb565_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) {
rgb565_flip_endian(&col, fb->format);
((uint16_t*)fb->buf)[x + y * fb->stride] = col;
}

STATIC uint32_t rgb565_getpixel(const mp_obj_framebuf_t *fb, int x, int y) {
return ((uint16_t*)fb->buf)[x + y * fb->stride];
uint32_t col = ((uint16_t*)fb->buf)[x + y * fb->stride];
rgb565_flip_endian(&col, fb->format);
return col;
}

STATIC void rgb565_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) {
rgb565_flip_endian(&col, fb->format);
uint16_t *b = &((uint16_t*)fb->buf)[x + y * fb->stride];

while (h--) {
for (int ww = w; ww; --ww) {
*b++ = col;
Expand Down Expand Up @@ -228,14 +241,25 @@ STATIC void gs8_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int

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_BE] = {rgb565_setpixel, rgb565_getpixel, rgb565_fill_rect},
[FRAMEBUF_RGB565_LE] = {rgb565_setpixel, rgb565_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},
[FRAMEBUF_MHLSB] = {mono_horiz_setpixel, mono_horiz_getpixel, mono_horiz_fill_rect},
[FRAMEBUF_MHMSB] = {mono_horiz_setpixel, mono_horiz_getpixel, mono_horiz_fill_rect},
};

STATIC inline size_t bytes_per_pixel(const mp_obj_framebuf_t *fb) {
switch (fb->format) {
case FRAMEBUF_RGB565_BE:
case FRAMEBUF_RGB565_LE:
return 2;
default:
return 1;
}
}

static inline void setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) {
formats[fb->format].setpixel(fb, x, y, col);
}
Expand Down Expand Up @@ -281,7 +305,8 @@ STATIC mp_obj_t framebuf_make_new(const mp_obj_type_t *type, size_t n_args, size

switch (o->format) {
case FRAMEBUF_MVLSB:
case FRAMEBUF_RGB565:
case FRAMEBUF_RGB565_BE:
case FRAMEBUF_RGB565_LE:
break;
case FRAMEBUF_MHLSB:
case FRAMEBUF_MHMSB:
Expand All @@ -306,7 +331,7 @@ STATIC mp_int_t framebuf_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo,
(void)flags;
mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(self_in);
bufinfo->buf = self->buf;
bufinfo->len = self->stride * self->height * (self->format == FRAMEBUF_RGB565 ? 2 : 1);
bufinfo->len = self->stride * self->height * bytes_per_pixel(self);
bufinfo->typecode = 'B'; // view framebuf as bytes
return 0;
}
Expand Down Expand Up @@ -630,7 +655,13 @@ STATIC const mp_rom_map_elem_t framebuf_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_FrameBuffer1), MP_ROM_PTR(&legacy_framebuffer1_obj) },
{ 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_BIG
{ MP_ROM_QSTR(MP_QSTR_RGB565), MP_ROM_INT(FRAMEBUF_RGB565_BE) },
#else
{ MP_ROM_QSTR(MP_QSTR_RGB565), MP_ROM_INT(FRAMEBUF_RGB565_LE) },
#endif
{ MP_ROM_QSTR(MP_QSTR_RGB565_BE), MP_ROM_INT(FRAMEBUF_RGB565_BE) },
{ MP_ROM_QSTR(MP_QSTR_RGB565_LE), MP_ROM_INT(FRAMEBUF_RGB565_LE) },
{ 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) },
Expand Down
114 changes: 66 additions & 48 deletions tests/extmod/framebuf16.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,56 +4,74 @@
print("SKIP")
raise SystemExit

def printbuf():

def printbuf(buf, w, h):
print("--8<--")
for y in range(h):
print(buf[y * w * 2:(y + 1) * w * 2])
print("-->8--")

w = 4
h = 5
buf = bytearray(w * h * 2)
fbuf = framebuf.FrameBuffer(buf, w, h, framebuf.RGB565)

# 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()

# 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()

w2 = 2
h2 = 3
buf2 = bytearray(w2 * h2 * 2)
fbuf2 = framebuf.FrameBuffer(buf2, w2, h2, framebuf.RGB565)

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()

def test_basic():
w = 4
h = 5
buf = bytearray(w * h * 2)
fbuf = framebuf.FrameBuffer(buf, w, h, framebuf.RGB565)

# fill
fbuf.fill(0xffff)
printbuf(buf, w, h)
fbuf.fill(0x0000)
printbuf(buf, w, h)

# put pixel
fbuf.pixel(0, 0, 0xeeee)
fbuf.pixel(3, 0, 0xee00)
fbuf.pixel(0, 4, 0x00ee)
fbuf.pixel(3, 4, 0x0ee0)
printbuf(buf, w, h)

# get pixel
print(fbuf.pixel(0, 4), fbuf.pixel(1, 1))

# scroll
fbuf.fill(0x0000)
fbuf.pixel(2, 2, 0xffff)
printbuf(buf, w, h)
fbuf.scroll(0, 1)
printbuf(buf, w, h)
fbuf.scroll(1, 0)
printbuf(buf, w, h)
fbuf.scroll(-1, -2)
printbuf(buf, w, h)

w2 = 2
h2 = 3
buf2 = bytearray(w2 * h2 * 2)
fbuf2 = framebuf.FrameBuffer(buf2, w2, h2, framebuf.RGB565)

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(buf, w, h)


def test_endian():
for endian in (framebuf.RGB565_BE, framebuf.RGB565_LE,):
w = 4
h = 4
buf = bytearray(w * h * 2)
fbuf = framebuf.FrameBuffer(buf, w, h, endian)
fbuf.fill_rect(1, 1, 2, 2, 0xabcd)
fbuf.pixel(2, 2, 0xdcba)
printbuf(buf, w, h)


test_basic()
test_endian()
12 changes: 12 additions & 0 deletions tests/extmod/framebuf16.py.exp
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,15 @@ 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'\x00\x00\x00\x00\x00\x00\x00\x00')
bytearray(b'\x00\x00\xab\xcd\xab\xcd\x00\x00')
bytearray(b'\x00\x00\xab\xcd\xdc\xba\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\xcd\xab\xcd\xab\x00\x00')
bytearray(b'\x00\x00\xcd\xab\xba\xdc\x00\x00')
bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00')
-->8--
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy