Skip to content

Commit a081b49

Browse files
committed
extmod/modframebuf: Optimise fill and fill_rect methods.
Fill is a very common operation (eg to clear the screen) and it is worth optimising it, by providing a specialised fill_rect function for each framebuffer format. This patch improved the speed of fill by 10 times for a 16-bit display with 160*128 pixels.
1 parent 81e171b commit a081b49

File tree

1 file changed

+29
-12
lines changed

1 file changed

+29
-12
lines changed

extmod/modframebuf.c

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,12 @@ typedef struct _mp_obj_framebuf_t {
4444

4545
typedef void (*setpixel_t)(const mp_obj_framebuf_t*, int, int, uint32_t);
4646
typedef uint32_t (*getpixel_t)(const mp_obj_framebuf_t*, int, int);
47+
typedef void (*fill_rect_t)(const mp_obj_framebuf_t *, int, int, int, int, uint32_t);
4748

4849
typedef struct _mp_framebuf_p_t {
4950
setpixel_t setpixel;
5051
getpixel_t getpixel;
52+
fill_rect_t fill_rect;
5153
} mp_framebuf_p_t;
5254

5355
// Functions for MVLSB format
@@ -62,6 +64,18 @@ STATIC uint32_t mvlsb_getpixel(const mp_obj_framebuf_t *fb, int x, int y) {
6264
return (((uint8_t*)fb->buf)[(y >> 3) * fb->stride + x] >> (y & 0x07)) & 0x01;
6365
}
6466

67+
STATIC void mvlsb_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) {
68+
while (h--) {
69+
uint8_t *b = &((uint8_t*)fb->buf)[(y >> 3) * fb->stride + x];
70+
uint8_t offset = y & 0x07;
71+
for (int ww = w; ww; --ww) {
72+
*b = (*b & ~(0x01 << offset)) | ((col != 0) << offset);
73+
++b;
74+
}
75+
++y;
76+
}
77+
}
78+
6579
// Functions for RGB565 format
6680

6781
STATIC void rgb565_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t color) {
@@ -72,13 +86,23 @@ STATIC uint32_t rgb565_getpixel(const mp_obj_framebuf_t *fb, int x, int y) {
7286
return ((uint16_t*)fb->buf)[x + y * fb->stride];
7387
}
7488

89+
STATIC void rgb565_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t colour) {
90+
uint16_t *b = &((uint16_t*)fb->buf)[x + y * fb->stride];
91+
while (h--) {
92+
for (int ww = w; ww; --ww) {
93+
*b++ = colour;
94+
}
95+
b += fb->stride - w;
96+
}
97+
}
98+
7599
// constants for formats
76100
#define FRAMEBUF_MVLSB (0)
77101
#define FRAMEBUF_RGB565 (1)
78102

79103
STATIC mp_framebuf_p_t formats[] = {
80-
[FRAMEBUF_MVLSB] = {mvlsb_setpixel, mvlsb_getpixel},
81-
[FRAMEBUF_RGB565] = {rgb565_setpixel, rgb565_getpixel},
104+
[FRAMEBUF_MVLSB] = {mvlsb_setpixel, mvlsb_getpixel, mvlsb_fill_rect},
105+
[FRAMEBUF_RGB565] = {rgb565_setpixel, rgb565_getpixel, rgb565_fill_rect},
82106
};
83107

84108
static inline void setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t color) {
@@ -123,11 +147,7 @@ STATIC mp_obj_t framebuf_make_new(const mp_obj_type_t *type, size_t n_args, size
123147
STATIC mp_obj_t framebuf_fill(mp_obj_t self_in, mp_obj_t col_in) {
124148
mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(self_in);
125149
mp_int_t col = mp_obj_get_int(col_in);
126-
for (int y = 0; y < self->height; ++y) {
127-
for (int x = 0; x < self->width; ++x) {
128-
setpixel(self, x, y, col);
129-
}
130-
}
150+
formats[self->format].fill_rect(self, 0, 0, self->width, self->height, col);
131151
return mp_const_none;
132152
}
133153
STATIC MP_DEFINE_CONST_FUN_OBJ_2(framebuf_fill_obj, framebuf_fill);
@@ -153,11 +173,8 @@ STATIC mp_obj_t framebuf_fill_rect(size_t n_args, const mp_obj_t *args) {
153173
x = MAX(MIN(x, self->width), 0);
154174
y = MAX(MIN(y, self->height), 0);
155175

156-
for (; y < yend; ++y) {
157-
for (int xc = x; xc < xend; ++xc) {
158-
setpixel(self, xc, y, color);
159-
}
160-
}
176+
formats[self->format].fill_rect(self, x, y, xend - x, yend - y, color);
177+
161178
return mp_const_none;
162179
}
163180
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_fill_rect_obj, 6, 6, framebuf_fill_rect);

0 commit comments

Comments
 (0)