summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwarriorofwire <3454741+WarriorOfWire@users.noreply.github.com>2020-05-12 21:55:18 -0700
committerwarriorofwire <3454741+WarriorOfWire@users.noreply.github.com>2020-05-18 13:32:06 -0700
commit4bbb80e31af4c5626d118995e36ade470935fafe (patch)
tree6a2403b124b68273b7c9f3dfb181a1232c730887
parent2314f988b180615439635ec30e81f80085724c2f (diff)
vectorio: speed up polygon
This change takes polygon from 126k pixels per second fill to 240k pps fill on a reference 5 point star 50x66px polygon, updating both location and shape at 10hz. Tested on an m4 express feather. As a curiosity, the flat-out fill rate of a shape whose get_pixel is `return 0;` fills just shy of 375k pixels per second.
-rw-r--r--shared-bindings/vectorio/Polygon.c42
-rw-r--r--shared-module/vectorio/Polygon.c79
-rw-r--r--shared-module/vectorio/Polygon.h5
3 files changed, 65 insertions, 61 deletions
diff --git a/shared-bindings/vectorio/Polygon.c b/shared-bindings/vectorio/Polygon.c
index 5f4d85e21..e9e90942a 100644
--- a/shared-bindings/vectorio/Polygon.c
+++ b/shared-bindings/vectorio/Polygon.c
@@ -15,41 +15,6 @@
// #define VECTORIO_POLYGON_DEBUG(...) mp_printf(&mp_plat_print __VA_OPT__(,) __VA_ARGS__)
-// Converts a list of points tuples to a flat list of ints for speedier internal use.
-// Also validates the points.
-static mp_obj_t _to_points_list(mp_obj_t points_tuple_list) {
- size_t len = 0;
- mp_obj_t *items;
- mp_obj_list_get(points_tuple_list, &len, &items);
- VECTORIO_POLYGON_DEBUG("polygon_points_list len: %d\n", len);
-
- if ( len == 0 ) {
- mp_raise_TypeError_varg(translate("empty %q list"), MP_QSTR_point);
- }
-
- mp_obj_t points_list = mp_obj_new_list(0, NULL);
-
- for ( size_t i = 0; i < len; ++i) {
- size_t tuple_len = 0;
- mp_obj_t *tuple_items;
- mp_obj_tuple_get(items[i], &tuple_len, &tuple_items);
-
- if (tuple_len != 2) {
- mp_raise_ValueError_varg(translate("%q must be a tuple of length 2"), MP_QSTR_point);
- }
- int value;
- if (!mp_obj_get_int_maybe(tuple_items[0], &value)) {
- mp_raise_ValueError_varg(translate("unsupported %q type"), MP_QSTR_point);
- }
- mp_obj_list_append(points_list, MP_OBJ_NEW_SMALL_INT(value));
- if (!mp_obj_get_int_maybe(tuple_items[1], &value)) {
- mp_raise_ValueError_varg(translate("unsupported %q type"), MP_QSTR_point);
- }
- mp_obj_list_append(points_list, MP_OBJ_NEW_SMALL_INT(value));
- }
- return points_list;
-}
-//| from typing import List, Tuple
//|
//| class Polygon:
//| def __init__(self, points: List[ Tuple[ x, y ], ... ] ):
@@ -68,12 +33,11 @@ static mp_obj_t vectorio_polygon_make_new(const mp_obj_type_t *type, size_t n_ar
if (!MP_OBJ_IS_TYPE(args[ARG_points_list].u_obj, &mp_type_list)) {
mp_raise_TypeError_varg(translate("%q list must be a list"), MP_QSTR_point);
}
- mp_obj_t points_list = _to_points_list(args[ARG_points_list].u_obj);
vectorio_polygon_t *self = m_new_obj(vectorio_polygon_t);
self->base.type = &vectorio_polygon_type;
- common_hal_vectorio_polygon_construct(self, points_list);
+ common_hal_vectorio_polygon_construct(self, args[ARG_points_list].u_obj);
return MP_OBJ_FROM_PTR(self);
}
@@ -104,9 +68,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(vectorio_polygon_get_points_obj, vectorio_polygon_obj_
STATIC mp_obj_t vectorio_polygon_obj_set_points(mp_obj_t self_in, mp_obj_t points) {
vectorio_polygon_t *self = MP_OBJ_TO_PTR(self_in);
- mp_obj_t points_list = _to_points_list(points);
-
- common_hal_vectorio_polygon_set_points(self, points_list);
+ common_hal_vectorio_polygon_set_points(self, points);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(vectorio_polygon_set_points_obj, vectorio_polygon_obj_set_points);
diff --git a/shared-module/vectorio/Polygon.c b/shared-module/vectorio/Polygon.c
index 6722912c2..7e3a3acfe 100644
--- a/shared-module/vectorio/Polygon.c
+++ b/shared-module/vectorio/Polygon.c
@@ -4,6 +4,8 @@
#include "shared-module/displayio/area.h"
#include "py/runtime.h"
+#include "py/gc.h"
+
#include "stdlib.h"
#include <stdio.h>
@@ -12,10 +14,57 @@
// #define VECTORIO_POLYGON_DEBUG(...) mp_printf(&mp_plat_print __VA_OPT__(,) __VA_ARGS__)
+// Converts a list of points tuples to a flat list of ints for speedier internal use.
+// Also validates the points.
+static void _clobber_points_list(vectorio_polygon_t *self, mp_obj_t points_tuple_list) {
+ size_t len = 0;
+ mp_obj_t *items;
+ mp_obj_list_get(points_tuple_list, &len, &items);
+ VECTORIO_POLYGON_DEBUG("polygon_points_list len: %d\n", len);
+
+ if ( len < 3 ) {
+ mp_raise_TypeError_varg(translate("Polygon needs at least 3 points"));
+ }
+
+ if ( self->len < 2*len ) {
+ if ( self->points_list != NULL ) {
+ gc_free( self->points_list );
+ }
+ self->points_list = gc_alloc( 2 * len * sizeof(int), false, false );
+ }
+ self->len = 2*len;
+
+ for ( size_t i = 0; i < len; ++i) {
+ size_t tuple_len = 0;
+ mp_obj_t *tuple_items;
+ mp_obj_tuple_get(items[i], &tuple_len, &tuple_items);
+
+ if (tuple_len != 2) {
+ mp_raise_ValueError_varg(translate("%q must be a tuple of length 2"), MP_QSTR_point);
+ }
+ if (!mp_obj_get_int_maybe(tuple_items[0], &self->points_list[2*i])) {
+ self->len = 0;
+ gc_free( self->points_list );
+ self->points_list = NULL;
+ mp_raise_ValueError_varg(translate("unsupported %q type"), MP_QSTR_point);
+ }
+ if (!mp_obj_get_int_maybe(tuple_items[1], &self->points_list[2*i + 1])) {
+ self->len = 0;
+ gc_free( self->points_list );
+ self->points_list = NULL;
+ mp_raise_ValueError_varg(translate("unsupported %q type"), MP_QSTR_point);
+ }
+ }
+}
+
+
+
void common_hal_vectorio_polygon_construct(vectorio_polygon_t *self, mp_obj_t points_list) {
VECTORIO_POLYGON_DEBUG("%p polygon_construct\n", self);
- self->points_list = points_list;
+ self->points_list = NULL;
+ self->len = 0;
self->on_dirty.obj = NULL;
+ _clobber_points_list( self, points_list );
}
@@ -23,7 +72,7 @@ mp_obj_t common_hal_vectorio_polygon_get_points(vectorio_polygon_t *self) {
return self->points_list;
}
void common_hal_vectorio_polygon_set_points(vectorio_polygon_t *self, mp_obj_t points_list) {
- self->points_list = points_list;
+ _clobber_points_list( self, points_list );
if (self->on_dirty.obj != NULL) {
self->on_dirty.event(self->on_dirty.obj);
}
@@ -38,21 +87,16 @@ void common_hal_vectorio_polygon_set_on_dirty(vectorio_polygon_t *self, vectorio
void common_hal_vectorio_polygon_get_area(void *polygon, displayio_area_t *area) {
- VECTORIO_POLYGON_DEBUG("%p polygon get_area", polygon);
vectorio_polygon_t *self = polygon;
- size_t len;
- mp_obj_t *points;
- mp_obj_list_get(self->points_list, &len, &points);
- VECTORIO_POLYGON_DEBUG(" len: %2d, points: %d\n", len, len/2);
area->x1 = SHRT_MAX;
area->y1 = SHRT_MAX;
area->x2 = SHRT_MIN;
area->y2 = SHRT_MIN;
- for (size_t i=0; i < len; ++i) {
- mp_int_t x = mp_obj_get_int(points[i]);
+ for (size_t i=0; i < self->len; ++i) {
+ int x = self->points_list[i];
++i;
- mp_int_t y = mp_obj_get_int(points[i]);
+ int y = self->points_list[i];
if (x <= area->x1) area->x1 = x-1;
if (y <= area->y1) area->y1 = y-1;
if (x >= area->x2) area->x2 = x+1;
@@ -73,22 +117,19 @@ __attribute__((always_inline)) static inline int line_side( mp_int_t x1, mp_int_
uint32_t common_hal_vectorio_polygon_get_pixel(void *obj, int16_t x, int16_t y) {
VECTORIO_POLYGON_DEBUG("%p polygon get_pixel %d, %d\n", obj, x, y);
vectorio_polygon_t *self = obj;
- size_t len;
- mp_obj_t *points;
- mp_obj_list_get(self->points_list, &len, &points);
- if (len == 0) {
+ if (self->len == 0) {
return 0;
}
int winding_number = 0;
- mp_int_t x1 = mp_obj_get_int(points[0]);
- mp_int_t y1 = mp_obj_get_int(points[1]);
- for (size_t i=2; i <= len + 1; ++i) {
+ int x1 = self->points_list[0];
+ int y1 = self->points_list[1];
+ for (size_t i=2; i <= self->len + 1; ++i) {
VECTORIO_POLYGON_DEBUG(" {(%3d, %3d),", x1, y1);
- mp_int_t x2 = mp_obj_get_int(points[i % len]);
+ int x2 = self->points_list[i % self->len];
++i;
- mp_int_t y2 = mp_obj_get_int(points[i % len]);
+ int y2 = self->points_list[i % self->len];
VECTORIO_POLYGON_DEBUG(" (%3d, %3d)}\n", x2, y2);
if ( y1 <= y ) {
if ( y2 > y && line_side(x1, y1, x2, y2, x, y) > 0 ) {
diff --git a/shared-module/vectorio/Polygon.h b/shared-module/vectorio/Polygon.h
index 1aef854a7..70de9036d 100644
--- a/shared-module/vectorio/Polygon.h
+++ b/shared-module/vectorio/Polygon.h
@@ -8,8 +8,9 @@
typedef struct {
mp_obj_base_t base;
- // A micropython List[ x, y, ... ]
- mp_obj_t points_list;
+ // An int array[ x, y, ... ]
+ int *points_list;
+ size_t len;
vectorio_event_t on_dirty;
} vectorio_polygon_t;