Skip to content

Commit 2e1c964

Browse files
committed
PicoVector: Runtime buffer allocation.
1 parent 225ecfc commit 2e1c964

File tree

2 files changed

+60
-30
lines changed

2 files changed

+60
-30
lines changed

libraries/pico_vector/pico_vector.hpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,13 @@ namespace pimoroni {
3434

3535
public:
3636
static PicoGraphics *graphics;
37-
PicoVector(PicoGraphics *graphics, void *mem = nullptr) {
37+
PicoVector(PicoGraphics *graphics) {
3838
PicoVector::graphics = graphics;
3939

40+
// TODO: Make these configurable?
41+
// Tile buffer size, Max nodes per scanline
42+
pp_init(16, 16);
43+
4044
pp_tile_callback(PicoVector::tile_callback);
4145

4246
set_antialiasing(graphics->supports_alpha_blend() ? PP_AA_X4 : PP_AA_NONE);
@@ -48,11 +52,15 @@ namespace pimoroni {
4852
text_metrics.letter_spacing = 95;
4953
text_metrics.word_spacing = 200;
5054
text_metrics.size = 48;
51-
// Shoud be set before rendering chars
55+
// Should be set before rendering chars
5256
//text_metrics.transform = (pp_mat3_t *)af_malloc(sizeof(pp_mat3_t));
5357
//*text_metrics.transform = pp_mat3_identity();
5458
}
5559

60+
~PicoVector() {
61+
pp_deinit();
62+
}
63+
5664
static void tile_callback(const pp_tile_t *tile) {
5765
// TODO: we're using a cast here to avoid a hard dependency link between
5866
// PicoGraphics and PicoVector. These types might subtly mismatch, though...

libraries/pico_vector/pretty-poly.h

Lines changed: 50 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,6 @@
4040
#define PP_COORD_TYPE float
4141
#endif
4242

43-
#ifndef PP_MAX_NODES_PER_SCANLINE
44-
#define PP_MAX_NODES_PER_SCANLINE 16
45-
#endif
46-
47-
#ifndef PP_TILE_BUFFER_SIZE
48-
#define PP_TILE_BUFFER_SIZE 64
49-
#endif
50-
5143
#ifndef PP_SCALE_TO_ALPHA
5244
#define PP_SCALE_TO_ALPHA 1
5345
#endif
@@ -126,6 +118,8 @@ void pp_poly_merge(pp_poly_t *p, pp_poly_t *m);
126118
// user settings
127119
typedef void (*pp_tile_callback_t)(const pp_tile_t *tile);
128120

121+
extern uint32_t _pp_tile_buffer_size;
122+
129123
extern pp_rect_t _pp_clip;
130124
extern pp_tile_callback_t _pp_tile_callback;
131125
extern pp_antialias_t _pp_antialias;
@@ -137,6 +131,9 @@ void pp_antialias(pp_antialias_t antialias);
137131
pp_mat3_t *pp_transform(pp_mat3_t *transform);
138132
void pp_render(pp_poly_t *polygon);
139133

134+
void pp_init(uint32_t tile_buffer_size, uint32_t max_nodes_per_scanline);
135+
void pp_deinit();
136+
140137

141138
#ifdef __cplusplus
142139
}
@@ -257,7 +254,7 @@ pp_rect_t pp_rect_transform(pp_rect_t *r, pp_mat3_t *m) {
257254

258255
// pp_tile_t implementation
259256
uint8_t pp_tile_get(const pp_tile_t *tile, const int32_t x, const int32_t y) {
260-
return tile->data[(x - tile->x) + (y - tile->y) * PP_TILE_BUFFER_SIZE];
257+
return tile->data[(x - tile->x) + (y - tile->y) * _pp_tile_buffer_size];
261258
}
262259

263260
pp_poly_t *pp_poly_new() {
@@ -380,19 +377,40 @@ pp_rect_t pp_poly_bounds(pp_poly_t *p) {
380377
return b;
381378
}
382379

380+
uint32_t _pp_tile_buffer_size = 0;
381+
uint32_t _pp_max_nodes_per_scanline = 0;
382+
383383
// buffer that each tile is rendered into before callback
384384
// allocate one extra byte to allow a small optimization in the row renderer
385-
uint8_t pp_tile_buffer[PP_TILE_BUFFER_SIZE * PP_TILE_BUFFER_SIZE];
385+
uint8_t *pp_tile_buffer;
386+
//uint8_t pp_tile_buffer[PP_TILE_BUFFER_SIZE * PP_TILE_BUFFER_SIZE];
386387

387388
// polygon node buffer handles at most 16 line intersections per scanline
388389
// is this enough for cjk/emoji? (requires a 2kB buffer)
389-
int32_t pp_nodes[PP_TILE_BUFFER_SIZE * 4][PP_MAX_NODES_PER_SCANLINE * 2];
390-
uint32_t pp_node_counts[PP_TILE_BUFFER_SIZE * 4];
390+
int32_t *pp_nodes;
391+
uint32_t *pp_node_counts;
392+
//int32_t pp_nodes[PP_TILE_BUFFER_SIZE * 4][PP_MAX_NODES_PER_SCANLINE * 2];
393+
//uint32_t pp_node_counts[PP_TILE_BUFFER_SIZE * 4];
391394

392395
uint8_t _pp_alpha_map_none[2] = {0, 255};
393396
uint8_t _pp_alpha_map_x4[5] = {0, 63, 127, 190, 255};
394397
uint8_t _pp_alpha_map_x16[17] = {0, 16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240, 255};
395398

399+
void pp_init(uint32_t tile_buffer_size, uint32_t max_nodes_per_scanline) {
400+
_pp_tile_buffer_size = tile_buffer_size;
401+
_pp_max_nodes_per_scanline = max_nodes_per_scanline;
402+
pp_tile_buffer = (uint8_t *)PP_MALLOC(tile_buffer_size * tile_buffer_size);
403+
// tile_buffer_size * 4 | max_nodes_per_scanline * 2
404+
pp_nodes = (int32_t *)PP_MALLOC(tile_buffer_size * 4 * max_nodes_per_scanline * 2 * sizeof(int32_t));
405+
pp_node_counts = (uint32_t *)PP_MALLOC(tile_buffer_size * 4 * sizeof(uint32_t));
406+
}
407+
408+
void pp_deinit() {
409+
PP_FREE(pp_tile_buffer);
410+
PP_FREE(pp_nodes);
411+
PP_FREE(pp_node_counts);
412+
}
413+
396414
void pp_clip(int32_t x, int32_t y, int32_t w, int32_t h) {
397415
_pp_clip = (pp_rect_t){.x = x, .y = y, .w = w, .h = h};
398416
}
@@ -482,15 +500,18 @@ void add_line_segment_to_nodes(const pp_point_t start, const pp_point_t end, pp_
482500
// }
483501
// #else
484502
// loop over scanlines
503+
485504
while(count--) {
505+
int32_t *pp_scanline_nodes = &pp_nodes[y * _pp_max_nodes_per_scanline * 2];
506+
486507
// consume accumulated error
487508
while(e > dy) {e -= dy; x += xinc;}
488509

489510
// clamp node x value to tile bounds
490511
int nx = _pp_max(_pp_min(x, (tb->w << _pp_antialias)), 0);
491512
//debug(" + adding node at %d, %d\n", x, y);
492513
// add node to node list
493-
pp_nodes[y][pp_node_counts[y]++] = nx;
514+
pp_scanline_nodes[pp_node_counts[y]++] = nx;
494515

495516
// step to next scanline and accumulate error
496517
y++;
@@ -525,23 +546,24 @@ int compare_nodes(const void* a, const void* b) {
525546
}
526547

527548
pp_rect_t render_nodes(pp_rect_t *tb) {
528-
pp_rect_t rb = {PP_TILE_BUFFER_SIZE << _pp_antialias, PP_TILE_BUFFER_SIZE << _pp_antialias, 0, 0}; // render bounds
529-
int maxx = 0, minx = PP_TILE_BUFFER_SIZE << _pp_antialias;
549+
pp_rect_t rb = {_pp_tile_buffer_size << _pp_antialias, _pp_tile_buffer_size << _pp_antialias, 0, 0}; // render bounds
550+
int maxx = 0, minx = _pp_tile_buffer_size << _pp_antialias;
530551
debug(" + render tile %d, %d - %d, %d\n", tb->x, tb->y, tb->w, tb->h);
531552

532-
for(int y = 0; y < ((int)PP_TILE_BUFFER_SIZE << _pp_antialias); y++) {
553+
for(int y = 0; y < ((int)_pp_tile_buffer_size << _pp_antialias); y++) {
554+
int32_t *pp_scanline_nodes = &pp_nodes[y * _pp_max_nodes_per_scanline * 2];
533555

534556
// debug(" : row %d node count %d\n", y, pp_node_counts[y]);
535557

536558
if(pp_node_counts[y] == 0) continue; // no nodes on this raster line
537559

538-
qsort(&pp_nodes[y][0], pp_node_counts[y], sizeof(int), compare_nodes);
560+
qsort(pp_scanline_nodes, pp_node_counts[y], sizeof(int), compare_nodes);
539561

540-
unsigned char* row_data = &pp_tile_buffer[(y >> _pp_antialias) * PP_TILE_BUFFER_SIZE];
562+
unsigned char* row_data = &pp_tile_buffer[(y >> _pp_antialias) * _pp_tile_buffer_size];
541563

542564
for(uint32_t i = 0; i < pp_node_counts[y]; i += 2) {
543-
int sx = pp_nodes[y][i + 0];
544-
int ex = pp_nodes[y][i + 1];
565+
int sx = *pp_scanline_nodes++;
566+
int ex = *pp_scanline_nodes++;
545567

546568
if(sx == ex) { // empty span, nothing to do
547569
continue;
@@ -584,7 +606,7 @@ pp_rect_t render_nodes(pp_rect_t *tb) {
584606
if(_pp_antialias == 2) p_alpha_map = _pp_alpha_map_x16;
585607
#if PP_SCALE_TO_ALPHA == 1
586608
for(int y = rb.y; y < rb.y + rb.h; y++) {
587-
unsigned char* row_data = &pp_tile_buffer[y * PP_TILE_BUFFER_SIZE + rb.x];
609+
unsigned char* row_data = &pp_tile_buffer[y * _pp_tile_buffer_size + rb.x];
588610
for(int x = rb.x; x < rb.x + rb.w; x++) {
589611
*row_data = p_alpha_map[*row_data];
590612
row_data++;
@@ -626,18 +648,18 @@ void pp_render(pp_poly_t *polygon) {
626648

627649
// iterate over tiles
628650
debug(" - processing tiles\n");
629-
for(int32_t y = pb.y; y < pb.y + pb.h; y += PP_TILE_BUFFER_SIZE) {
630-
for(int32_t x = pb.x; x < pb.x + pb.w; x += PP_TILE_BUFFER_SIZE) {
631-
pp_rect_t tb = (pp_rect_t){.x = x, .y = y, .w = PP_TILE_BUFFER_SIZE, .h = PP_TILE_BUFFER_SIZE};
651+
for(int32_t y = pb.y; y < pb.y + pb.h; y += _pp_tile_buffer_size) {
652+
for(int32_t x = pb.x; x < pb.x + pb.w; x += _pp_tile_buffer_size) {
653+
pp_rect_t tb = (pp_rect_t){.x = x, .y = y, .w = _pp_tile_buffer_size, .h = _pp_tile_buffer_size};
632654
tb = pp_rect_intersection(&tb, &_pp_clip);
633655
debug(" : %d, %d (%d x %d)\n", tb.x, tb.y, tb.w, tb.h);
634656

635657
// if no intersection then skip tile
636658
if(pp_rect_empty(&tb)) { debug(" : empty when clipped, skipping\n"); continue; }
637659

638660
// clear existing tile data and nodes
639-
memset(pp_node_counts, 0, sizeof(pp_node_counts));
640-
memset(pp_tile_buffer, 0, PP_TILE_BUFFER_SIZE * PP_TILE_BUFFER_SIZE);
661+
memset(pp_node_counts, 0, _pp_tile_buffer_size * 4 * sizeof(uint32_t));
662+
memset(pp_tile_buffer, 0, _pp_tile_buffer_size * _pp_tile_buffer_size);
641663

642664
// build the nodes for each pp_path_t
643665
pp_path_t *path = polygon->paths;
@@ -658,8 +680,8 @@ void pp_render(pp_poly_t *polygon) {
658680

659681
pp_tile_t tile = {
660682
.x = tb.x, .y = tb.y, .w = tb.w, .h = tb.h,
661-
.stride = PP_TILE_BUFFER_SIZE,
662-
.data = pp_tile_buffer + rb.x + (PP_TILE_BUFFER_SIZE * rb.y)
683+
.stride = _pp_tile_buffer_size,
684+
.data = pp_tile_buffer + rb.x + (_pp_tile_buffer_size * rb.y)
663685
};
664686

665687
_pp_tile_callback(&tile);

0 commit comments

Comments
 (0)