extmod/modframebuf: Enable blit between different formats via a palette.

This achieves a substantial performance improvement when rendering glyphs
to color displays, the benefit increasing proportional to the number of
pixels in the glyph.
pull/7711/head
Peter Hinch 2021-08-18 20:05:25 +01:00 zatwierdzone przez Damien George
rodzic 996f703166
commit 2296df0a32
4 zmienionych plików z 59 dodań i 5 usunięć

Wyświetl plik

@ -103,16 +103,23 @@ Other methods
Shift the contents of the FrameBuffer by the given vector. This may Shift the contents of the FrameBuffer by the given vector. This may
leave a footprint of the previous colors in the FrameBuffer. leave a footprint of the previous colors in the FrameBuffer.
.. method:: FrameBuffer.blit(fbuf, x, y[, key]) .. method:: FrameBuffer.blit(fbuf, x, y, key=-1, palette=None)
Draw another FrameBuffer on top of the current one at the given coordinates. Draw another FrameBuffer on top of the current one at the given coordinates.
If *key* is specified then it should be a color integer and the If *key* is specified then it should be a color integer and the
corresponding color will be considered transparent: all pixels with that corresponding color will be considered transparent: all pixels with that
color value will not be drawn. color value will not be drawn.
This method works between FrameBuffer instances utilising different formats, The *palette* argument enables blitting between FrameBuffers with differing
but the resulting colors may be unexpected due to the mismatch in color formats. Typical usage is to render a monochrome or grayscale glyph/icon to
formats. a color display. The *palette* is a FrameBuffer instance whose format is
that of the current FrameBuffer. The *palette* height is one pixel and its
pixel width is the number of colors in the source FrameBuffer. The *palette*
for an N-bit source needs 2**N pixels; the *palette* for a monochrome source
would have 2 pixels representing background and foreground colors. The
application assigns a color to each pixel in the *palette*. The color of the
current pixel will be that of that *palette* pixel whose x position is the
color of the corresponding source pixel.
Constants Constants
--------- ---------

Wyświetl plik

@ -491,6 +491,10 @@ STATIC mp_obj_t framebuf_blit(size_t n_args, const mp_obj_t *args) {
if (n_args > 4) { if (n_args > 4) {
key = mp_obj_get_int(args[4]); key = mp_obj_get_int(args[4]);
} }
mp_obj_framebuf_t *palette = NULL;
if (n_args > 5 && args[5] != mp_const_none) {
palette = MP_OBJ_TO_PTR(mp_obj_cast_to_native_base(args[5], MP_OBJ_FROM_PTR(&mp_type_framebuf)));
}
if ( if (
(x >= self->width) || (x >= self->width) ||
@ -514,6 +518,9 @@ STATIC mp_obj_t framebuf_blit(size_t n_args, const mp_obj_t *args) {
int cx1 = x1; int cx1 = x1;
for (int cx0 = x0; cx0 < x0end; ++cx0) { for (int cx0 = x0; cx0 < x0end; ++cx0) {
uint32_t col = getpixel(source, cx1, y1); uint32_t col = getpixel(source, cx1, y1);
if (palette) {
col = getpixel(palette, col, 0);
}
if (col != (uint32_t)key) { if (col != (uint32_t)key) {
setpixel(self, cx0, y0, col); setpixel(self, cx0, y0, col);
} }
@ -523,7 +530,7 @@ STATIC mp_obj_t framebuf_blit(size_t n_args, const mp_obj_t *args) {
} }
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_blit_obj, 4, 5, framebuf_blit); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_blit_obj, 4, 6, framebuf_blit);
STATIC mp_obj_t framebuf_scroll(mp_obj_t self_in, mp_obj_t xstep_in, mp_obj_t ystep_in) { STATIC mp_obj_t framebuf_scroll(mp_obj_t self_in, mp_obj_t xstep_in, mp_obj_t ystep_in) {
mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(self_in);

Wyświetl plik

@ -0,0 +1,35 @@
# Test blit between different color spaces
try:
import framebuf, usys
except ImportError:
print("SKIP")
raise SystemExit
# Monochrome glyph/icon
w = 8
h = 8
cbuf = bytearray(w * h // 8)
fbc = framebuf.FrameBuffer(cbuf, w, h, framebuf.MONO_HLSB)
fbc.line(0, 0, 7, 7, 1)
# RGB565 destination
wd = 16
hd = 16
dest = bytearray(wd * hd * 2)
fbd = framebuf.FrameBuffer(dest, wd, hd, framebuf.RGB565)
wp = 2
bg = 0x1234
fg = 0xF800
pal = bytearray(wp * 2)
palette = framebuf.FrameBuffer(pal, wp, 1, framebuf.RGB565)
palette.pixel(0, 0, bg)
palette.pixel(1, 0, fg)
fbd.blit(fbc, 0, 0, -1, palette)
print(fbd.pixel(0, 0) == fg)
print(fbd.pixel(7, 7) == fg)
print(fbd.pixel(8, 8) == 0) # Ouside blit
print(fbd.pixel(0, 1) == bg)
print(fbd.pixel(1, 0) == bg)

Wyświetl plik

@ -0,0 +1,5 @@
True
True
True
True
True