Porównaj commity

...

2 Commity

Autor SHA1 Wiadomość Data
Phil Howard f19465587a PicoVector: Revert the tile buffer to be fixed.
Ensure that MicroPython doesn't ever place the tile buffer into PSRAM
and trash performance.
2024-11-18 13:58:54 +00:00
Phil Howard a6524a7fbe PicoVector: Runtime buffer allocation. 2024-11-15 12:42:44 +00:00
3 zmienionych plików z 41 dodań i 22 usunięć

Wyświetl plik

@ -34,9 +34,13 @@ namespace pimoroni {
public:
static PicoGraphics *graphics;
PicoVector(PicoGraphics *graphics, void *mem = nullptr) {
PicoVector(PicoGraphics *graphics) {
PicoVector::graphics = graphics;
// TODO: Make these configurable?
// Tile buffer size, Max nodes per scanline
pp_init(16);
pp_tile_callback(PicoVector::tile_callback);
set_antialiasing(graphics->supports_alpha_blend() ? PP_AA_X4 : PP_AA_NONE);
@ -48,11 +52,15 @@ namespace pimoroni {
text_metrics.letter_spacing = 95;
text_metrics.word_spacing = 200;
text_metrics.size = 48;
// Shoud be set before rendering chars
// Should be set before rendering chars
//text_metrics.transform = (pp_mat3_t *)af_malloc(sizeof(pp_mat3_t));
//*text_metrics.transform = pp_mat3_identity();
}
~PicoVector() {
pp_deinit();
}
static void tile_callback(const pp_tile_t *tile) {
// TODO: we're using a cast here to avoid a hard dependency link between
// PicoGraphics and PicoVector. These types might subtly mismatch, though...

Wyświetl plik

@ -40,10 +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
@ -137,6 +133,9 @@ void pp_antialias(pp_antialias_t antialias);
pp_mat3_t *pp_transform(pp_mat3_t *transform);
void pp_render(pp_poly_t *polygon);
void pp_init(uint32_t max_nodes_per_scanline);
void pp_deinit();
#ifdef __cplusplus
}
@ -380,19 +379,33 @@ pp_rect_t pp_poly_bounds(pp_poly_t *p) {
return b;
}
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
// This allocates 4k up-front to ensure it's stored in Pico's RAM
// Rather than potentially allocating into PSRAM at runtime and trashing perf
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;
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 max_nodes_per_scanline) {
_pp_max_nodes_per_scanline = max_nodes_per_scanline;
pp_nodes = (int32_t *)PP_MALLOC(PP_TILE_BUFFER_SIZE * 4 * max_nodes_per_scanline * 2 * sizeof(int32_t));
pp_node_counts = (uint32_t *)PP_MALLOC(PP_TILE_BUFFER_SIZE * 4 * sizeof(uint32_t));
}
void pp_deinit() {
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};
}
@ -482,7 +495,10 @@ void add_line_segment_to_nodes(const pp_point_t start, const pp_point_t end, pp_
// }
// #else
// loop over scanlines
while(count--) {
int32_t *pp_scanline_nodes = &pp_nodes[y * 4 * _pp_max_nodes_per_scanline * 2];
// consume accumulated error
while(e > dy) {e -= dy; x += xinc;}
@ -490,7 +506,7 @@ void add_line_segment_to_nodes(const pp_point_t start, const pp_point_t end, pp_
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++;
@ -530,18 +546,19 @@ pp_rect_t render_nodes(pp_rect_t *tb) {
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++) {
int32_t *pp_scanline_nodes = &pp_nodes[y * 4 * _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];
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;
@ -636,8 +653,8 @@ void pp_render(pp_poly_t *polygon) {
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, sizeof(pp_tile_buffer));
// build the nodes for each pp_path_t
pp_path_t *path = polygon->paths;

Wyświetl plik

@ -21,7 +21,6 @@ typedef struct _ModPicoGraphics_obj_t {
typedef struct _VECTOR_obj_t {
mp_obj_base_t base;
void *mem;
PicoVector *vector;
} _VECTOR_obj_t;
@ -545,12 +544,7 @@ mp_obj_t VECTOR_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw,
self->base.type = &VECTOR_type;
ModPicoGraphics_obj_t *graphics = (ModPicoGraphics_obj_t *)MP_OBJ_TO_PTR(args[ARG_picographics].u_obj);
// The PicoVector class calls `pretty_poly::init()` with the memory region
// it does not store a pointer to this, so we need to store one ourselves
// TODO: C Pretty Poly does not support runtime memory allocation
//self->mem = m_new(uint8_t, PicoVector::pretty_poly_buffer_size());
self->vector = m_new_class(PicoVector, graphics->graphics, self->mem);
self->vector = m_new_class(PicoVector, graphics->graphics);
return self;
}