@@ -52,7 +52,8 @@ static void mark(picogame_canvas_obj_t *cv, int lx1, int ly1, int lx2, int ly2)
5252// 8 calls/iteration). Inlining bloated them (circle was ~1.4 KB); a real call keeps
5353// them small. Shapes aren't the hot path (the sprite/tilemap blits don't use put).
5454static __attribute__((noinline )) void put (picogame_canvas_obj_t * cv , int x , int y , uint16_t c ) {
55- if (x >= 0 && y >= 0 && x < cv -> w && y < cv -> h ) {
55+ // Unsigned compares also reject negative coordinates.
56+ if ((unsigned )x < (unsigned )cv -> w && (unsigned )y < (unsigned )cv -> h ) {
5657 cv -> data [y * cv -> w + x ] = c ;
5758 }
5859}
@@ -306,7 +307,8 @@ void picogame_canvas_line(picogame_canvas_obj_t *cv, int x0, int y0, int x1, int
306307
307308// Clamp a row span to the surface and word-fill it (the span-pass idiom shared by the filled
308309// shapes; the per-pixel put() loops it replaced clipped and indexed every pixel).
309- static inline int64_t edge_slope (int32_t dx , int32_t dy ) {
310+ // Not inlined: each inlined copy carried both divides.
311+ static __attribute__((noinline )) int64_t edge_slope (int32_t dx , int32_t dy ) {
310312 if (dx >= -32768 && dx <= 32767 ) {
311313 return (int32_t )(dx << 16 ) / dy ;
312314 }
@@ -420,8 +422,15 @@ void picogame_canvas_fill_triangle(picogame_canvas_obj_t *cv,
420422 // top half: rows [Y0, Y1) walk edges A->C and A->B
421423 int ys = Y [0 ] < 0 ? 0 : Y [0 ];
422424 int ye = (Y [1 ] - 1 ) < (h - 1 ) ? (Y [1 ] - 1 ) : (h - 1 );
423- int64_t accAC = ((int64_t )X [0 ] << 16 ) + sAC * (ys - Y [0 ]);
424- int64_t acc2 = ((int64_t )X [0 ] << 16 ) + sAB * (ys - Y [0 ]);
425+ // skip is 0 unless the triangle is clipped at the top, so the int64 multiplies
426+ // usually do not run.
427+ int skip = ys - Y [0 ];
428+ int64_t accAC = (int64_t )X [0 ] << 16 ;
429+ int64_t acc2 = accAC ;
430+ if (skip ) {
431+ accAC += sAC * skip ;
432+ acc2 += sAB * skip ;
433+ }
425434 for (int y = ys ; y <= ye ; y ++ ) {
426435 int xac = (int )(accAC >> 16 );
427436 int xsh = (int )(acc2 >> 16 );
@@ -441,8 +450,12 @@ void picogame_canvas_fill_triangle(picogame_canvas_obj_t *cv,
441450 // bottom half: rows [Y1, Y2] walk edges A->C and B->C (a flat bottom degenerates to sBC=0)
442451 ys = Y [1 ] < 0 ? 0 : Y [1 ];
443452 ye = Y [2 ] < (h - 1 ) ? Y [2 ] : (h - 1 );
444- accAC = ((int64_t )X [0 ] << 16 ) + sAC * (ys - Y [0 ]);
445- acc2 = ((int64_t )X [1 ] << 16 ) + sBC * (ys - Y [1 ]);
453+ accAC = ((int64_t )X [0 ] << 16 ) + sAC * (ys - Y [0 ]); // spans the whole top half: rarely 0
454+ acc2 = (int64_t )X [1 ] << 16 ;
455+ skip = ys - Y [1 ];
456+ if (skip ) {
457+ acc2 += sBC * skip ;
458+ }
446459 for (int y = ys ; y <= ye ; y ++ ) {
447460 int xac = (int )(accAC >> 16 );
448461 int xsh = (int )(acc2 >> 16 );
@@ -581,6 +594,11 @@ void picogame_canvas_text(picogame_canvas_obj_t *cv, int x, int y, const char *t
581594 bool onebit = (sheet -> bits_per_value == 1 ); // terminalio.FONT is 1-bpp; other fonts take the fallback
582595 const uint8_t * sdata = (const uint8_t * )sheet -> data ;
583596 int sstride_b = sheet -> stride * 4 ; // atlas row stride in BYTES (stride counts uint32)
597+ // Copy to locals: the uint16_t store may alias sheet->bitmask, so the fields
598+ // would be reloaded for every pixel.
599+ int sx_shift = sheet -> x_shift ;
600+ size_t sx_mask = sheet -> x_mask ;
601+ uint16_t sbitmask = sheet -> bitmask ;
584602 for (const uint8_t * p = (const uint8_t * )text ; * p ; p ++ ) {
585603 uint8_t gi = fontio_builtinfont_get_glyph_index (f , * p );
586604 if (gi != 0xff ) { // 0xff = no glyph -> blank advance
@@ -596,7 +614,7 @@ void picogame_canvas_text(picogame_canvas_obj_t *cv, int x, int y, const char *t
596614 const uint8_t * srow = sdata + (size_t )sy * sstride_b ;
597615 for (int gx = gx0 ; gx < gx1 ; gx ++ ) {
598616 int sx = tx + gx ;
599- if ((srow [sx >> sheet -> x_shift ] >> (sheet -> x_mask - (sx & sheet -> x_mask ))) & sheet -> bitmask ) {
617+ if ((srow [sx >> sx_shift ] >> (sx_mask - (( size_t ) sx & sx_mask ))) & sbitmask ) {
600618 drow [gx ] = fg ;
601619 } else if (has_bg ) {
602620 drow [gx ] = bg ;
0 commit comments