summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2016-12-01 16:51:31 +1100
committerDamien George <damien.p.george@gmail.com>2016-12-01 16:51:31 +1100
commita081b49d55ef409d612666d79a97e79259c8adba (patch)
tree1a4e39aab4ca6e8cf674fb94e48d033a1ce6d151
parent81e171b7bb38cff377ca389cd6fb179aea325998 (diff)
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.
-rw-r--r--extmod/modframebuf.c41
1 files changed, 29 insertions, 12 deletions
diff --git a/extmod/modframebuf.c b/extmod/modframebuf.c
index e1bfe8310..840f331f3 100644
--- a/extmod/modframebuf.c
+++ b/extmod/modframebuf.c
@@ -44,10 +44,12 @@ typedef struct _mp_obj_framebuf_t {
typedef void (*setpixel_t)(const mp_obj_framebuf_t*, int, int, uint32_t);
typedef uint32_t (*getpixel_t)(const mp_obj_framebuf_t*, int, int);
+typedef void (*fill_rect_t)(const mp_obj_framebuf_t *, int, int, int, int, uint32_t);
typedef struct _mp_framebuf_p_t {
setpixel_t setpixel;
getpixel_t getpixel;
+ fill_rect_t fill_rect;
} mp_framebuf_p_t;
// Functions for MVLSB format
@@ -62,6 +64,18 @@ STATIC uint32_t mvlsb_getpixel(const mp_obj_framebuf_t *fb, int x, int y) {
return (((uint8_t*)fb->buf)[(y >> 3) * fb->stride + x] >> (y & 0x07)) & 0x01;
}
+STATIC void mvlsb_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) {
+ while (h--) {
+ uint8_t *b = &((uint8_t*)fb->buf)[(y >> 3) * fb->stride + x];
+ uint8_t offset = y & 0x07;
+ for (int ww = w; ww; --ww) {
+ *b = (*b & ~(0x01 << offset)) | ((col != 0) << offset);
+ ++b;
+ }
+ ++y;
+ }
+}
+
// Functions for RGB565 format
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) {
return ((uint16_t*)fb->buf)[x + y * fb->stride];
}
+STATIC void rgb565_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t colour) {
+ uint16_t *b = &((uint16_t*)fb->buf)[x + y * fb->stride];
+ while (h--) {
+ for (int ww = w; ww; --ww) {
+ *b++ = colour;
+ }
+ b += fb->stride - w;
+ }
+}
+
// constants for formats
#define FRAMEBUF_MVLSB (0)
#define FRAMEBUF_RGB565 (1)
STATIC mp_framebuf_p_t formats[] = {
- [FRAMEBUF_MVLSB] = {mvlsb_setpixel, mvlsb_getpixel},
- [FRAMEBUF_RGB565] = {rgb565_setpixel, rgb565_getpixel},
+ [FRAMEBUF_MVLSB] = {mvlsb_setpixel, mvlsb_getpixel, mvlsb_fill_rect},
+ [FRAMEBUF_RGB565] = {rgb565_setpixel, rgb565_getpixel, rgb565_fill_rect},
};
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
STATIC mp_obj_t framebuf_fill(mp_obj_t self_in, mp_obj_t col_in) {
mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(self_in);
mp_int_t col = mp_obj_get_int(col_in);
- for (int y = 0; y < self->height; ++y) {
- for (int x = 0; x < self->width; ++x) {
- setpixel(self, x, y, col);
- }
- }
+ formats[self->format].fill_rect(self, 0, 0, self->width, self->height, col);
return mp_const_none;
}
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) {
x = MAX(MIN(x, self->width), 0);
y = MAX(MIN(y, self->height), 0);
- for (; y < yend; ++y) {
- for (int xc = x; xc < xend; ++xc) {
- setpixel(self, xc, y, color);
- }
- }
+ formats[self->format].fill_rect(self, x, y, xend - x, yend - y, color);
+
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_fill_rect_obj, 6, 6, framebuf_fill_rect);