Skip to content

Commit

Permalink
PicoVector: Runtime buffer allocation.
Browse files Browse the repository at this point in the history
  • Loading branch information
Gadgetoid committed Nov 14, 2024
1 parent 225ecfc commit 44ca742
Showing 1 changed file with 45 additions and 28 deletions.
73 changes: 45 additions & 28 deletions libraries/pico_vector/pretty-poly.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,6 @@
#define PP_COORD_TYPE float
#endif

#ifndef PP_MAX_NODES_PER_SCANLINE
#define PP_MAX_NODES_PER_SCANLINE 16
#endif

#ifndef PP_TILE_BUFFER_SIZE
#define PP_TILE_BUFFER_SIZE 64
#endif

#ifndef PP_SCALE_TO_ALPHA
#define PP_SCALE_TO_ALPHA 1
#endif
Expand Down Expand Up @@ -257,7 +249,7 @@ pp_rect_t pp_rect_transform(pp_rect_t *r, pp_mat3_t *m) {

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

pp_poly_t *pp_poly_new() {
Expand Down Expand Up @@ -380,19 +372,40 @@ pp_rect_t pp_poly_bounds(pp_poly_t *p) {
return b;
}

uint32_t _pp_tile_buffer_size = 0;
uint32_t _pp_max_nodes_per_scanline = 0;

// buffer that each tile is rendered into before callback
// allocate one extra byte to allow a small optimization in the row renderer
uint8_t pp_tile_buffer[PP_TILE_BUFFER_SIZE * PP_TILE_BUFFER_SIZE];
uint8_t *pp_tile_buffer;
//uint8_t pp_tile_buffer[PP_TILE_BUFFER_SIZE * PP_TILE_BUFFER_SIZE];

// polygon node buffer handles at most 16 line intersections per scanline
// is this enough for cjk/emoji? (requires a 2kB buffer)
int32_t pp_nodes[PP_TILE_BUFFER_SIZE * 4][PP_MAX_NODES_PER_SCANLINE * 2];
uint32_t pp_node_counts[PP_TILE_BUFFER_SIZE * 4];
int32_t *pp_nodes;
uint32_t *pp_node_counts;
//int32_t pp_nodes[PP_TILE_BUFFER_SIZE * 4][PP_MAX_NODES_PER_SCANLINE * 2];
//uint32_t pp_node_counts[PP_TILE_BUFFER_SIZE * 4];

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

void pp_init(uint32_t tile_buffer_size, uint32_t max_nodes_per_scanline) {
_pp_tile_buffer_size = tile_buffer_size;
_pp_max_nodes_per_scanline = max_nodes_per_scanline;
pp_tile_buffer = (uint8_t *)PP_MALLOC(tile_buffer_size * tile_buffer_size);
// tile_buffer_size * 4 | max_nodes_per_scanline * 2
pp_nodes = (int32_t *)PP_MALLOC(tile_buffer_size * 4 * max_nodes_per_scanline * 2 * sizeof(int32_t));
pp_node_counts = (uint32_t *)PP_MALLOC(tile_buffer_size * 4 * sizeof(uint32_t));
}

void pp_deinit() {
PP_FREE(pp_tile_buffer);
PP_FREE(pp_nodes);
PP_FREE(pp_node_counts);
}

void pp_clip(int32_t x, int32_t y, int32_t w, int32_t h) {
_pp_clip = (pp_rect_t){.x = x, .y = y, .w = w, .h = h};
}
Expand Down Expand Up @@ -482,15 +495,18 @@ void add_line_segment_to_nodes(const pp_point_t start, const pp_point_t end, pp_
// }
// #else
// loop over scanlines

while(count--) {
int *pp_scanline_nodes = &pp_nodes[y * _pp_max_nodes_per_scanline * 2];

// consume accumulated error
while(e > dy) {e -= dy; x += xinc;}

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

// step to next scanline and accumulate error
y++;
Expand Down Expand Up @@ -525,23 +541,24 @@ int compare_nodes(const void* a, const void* b) {
}

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

for(int y = 0; y < ((int)PP_TILE_BUFFER_SIZE << _pp_antialias); y++) {
for(int y = 0; y < ((int)_pp_tile_buffer_size << _pp_antialias); y++) {
int *pp_scanline_nodes = &pp_nodes[y * _pp_max_nodes_per_scanline * 2];

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

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

qsort(&pp_nodes[y][0], pp_node_counts[y], sizeof(int), compare_nodes);
qsort(pp_scanline_nodes, pp_node_counts[y], sizeof(int), compare_nodes);

unsigned char* row_data = &pp_tile_buffer[(y >> _pp_antialias) * PP_TILE_BUFFER_SIZE];
unsigned char* row_data = &pp_tile_buffer[(y >> _pp_antialias) * _pp_tile_buffer_size];

for(uint32_t i = 0; i < pp_node_counts[y]; i += 2) {
int sx = pp_nodes[y][i + 0];
int ex = pp_nodes[y][i + 1];
int sx = *pp_scanline_nodes++;
int ex = *pp_scanline_nodes++;

if(sx == ex) { // empty span, nothing to do
continue;
Expand Down Expand Up @@ -584,7 +601,7 @@ pp_rect_t render_nodes(pp_rect_t *tb) {
if(_pp_antialias == 2) p_alpha_map = _pp_alpha_map_x16;
#if PP_SCALE_TO_ALPHA == 1
for(int y = rb.y; y < rb.y + rb.h; y++) {
unsigned char* row_data = &pp_tile_buffer[y * PP_TILE_BUFFER_SIZE + rb.x];
unsigned char* row_data = &pp_tile_buffer[y * _pp_tile_buffer_size + rb.x];
for(int x = rb.x; x < rb.x + rb.w; x++) {
*row_data = p_alpha_map[*row_data];
row_data++;
Expand Down Expand Up @@ -626,18 +643,18 @@ void pp_render(pp_poly_t *polygon) {

// iterate over tiles
debug(" - processing tiles\n");
for(int32_t y = pb.y; y < pb.y + pb.h; y += PP_TILE_BUFFER_SIZE) {
for(int32_t x = pb.x; x < pb.x + pb.w; x += PP_TILE_BUFFER_SIZE) {
pp_rect_t tb = (pp_rect_t){.x = x, .y = y, .w = PP_TILE_BUFFER_SIZE, .h = PP_TILE_BUFFER_SIZE};
for(int32_t y = pb.y; y < pb.y + pb.h; y += _pp_tile_buffer_size) {
for(int32_t x = pb.x; x < pb.x + pb.w; x += _pp_tile_buffer_size) {
pp_rect_t tb = (pp_rect_t){.x = x, .y = y, .w = _pp_tile_buffer_size, .h = _pp_tile_buffer_size};
tb = pp_rect_intersection(&tb, &_pp_clip);
debug(" : %d, %d (%d x %d)\n", tb.x, tb.y, tb.w, tb.h);

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

// clear existing tile data and nodes
memset(pp_node_counts, 0, sizeof(pp_node_counts));
memset(pp_tile_buffer, 0, PP_TILE_BUFFER_SIZE * PP_TILE_BUFFER_SIZE);
memset(pp_node_counts, 0, _pp_tile_buffer_size * 4 * sizeof(uint32_t));
memset(pp_tile_buffer, 0, _pp_tile_buffer_size * _pp_tile_buffer_size);

// build the nodes for each pp_path_t
pp_path_t *path = polygon->paths;
Expand All @@ -658,8 +675,8 @@ void pp_render(pp_poly_t *polygon) {

pp_tile_t tile = {
.x = tb.x, .y = tb.y, .w = tb.w, .h = tb.h,
.stride = PP_TILE_BUFFER_SIZE,
.data = pp_tile_buffer + rb.x + (PP_TILE_BUFFER_SIZE * rb.y)
.stride = _pp_tile_buffer_size,
.data = pp_tile_buffer + rb.x + (_pp_tile_buffer_size * rb.y)
};

_pp_tile_callback(&tile);
Expand Down

0 comments on commit 44ca742

Please sign in to comment.