tile.c
1 #include "tile.h" 2 3 #include "pico/platform.h" // for __not_in_flash 4 #include "hardware/interp.h" 5 6 #define __ram_func(foo) __not_in_flash(#foo) foo 7 8 static inline uint __attribute__((always_inline)) tile_log_size(tilesize_t size) { 9 return 3 + (int)size; 10 }; 11 12 static inline void setup_interp_tilemap_ptrs(interp_hw_t *interp, const uint8_t *row, uint x0, uint x_msb) { 13 // Setup interpolator to add 1 to tile x, mask it with tile x mask, and 14 // then add to tilemap row base. Since it's a preincrement, we walk the 15 // initial x back by 1. This isn't a very exciting use of interpolators, 16 // but it saves ~3 core registers for the pixel loops. 17 interp_config c = interp_default_config(); 18 interp_config_set_mask(&c, 0, x_msb); 19 interp_set_config(interp, 0, &c); 20 interp->accum[0] = x0; 21 interp->base[0] = 1; 22 interp->ctrl[1] = 0; 23 interp->base[2] = (uintptr_t)row; 24 } 25 26 void __ram_func(tile16)(uint16_t *scanbuf, const tilebg_t *bg, uint raster_y, uint raster_w) { 27 uint size_x_mask = (1u << bg->log_size_x) - 1; 28 uint size_y_mask = (1u << bg->log_size_y) - 1; 29 // Find render start/end point in tile space 30 // Note tx1 may be "past the end" -- that's fine, it's just used for limits 31 uint tx0 = bg->xscroll & size_x_mask; 32 uint tx1 = tx0 + raster_w; 33 uint ty = (bg->yscroll + raster_y) & size_y_mask; 34 35 const uint8_t *tilemap_row_ty = bg->tilemap + (ty >> tile_log_size(bg->tilesize) 36 << (bg->log_size_x - tile_log_size(bg->tilesize))); 37 uint tile_x_at_tx0 = tx0 >> tile_log_size(bg->tilesize); 38 uint tile_x_msb = bg->log_size_x - tile_log_size(bg->tilesize) - 1; 39 40 // NOTE this clobbers interp1, currently this will cause issues if you try 41 // to run tile code and certain TMDS encode loops on the same core. Could 42 // be fixed by save/restore, at the cost of some performance. 43 setup_interp_tilemap_ptrs(interp1_hw, tilemap_row_ty, tile_x_at_tx0, tile_x_msb); 44 45 // Apply intra-tile y offset in advance, since this will be the same for 46 // all pixels of all tiles we render in this call. 47 uint tilesize = 1u << tile_log_size(bg->tilesize); 48 const uint16_t *tileset_y_offs = (const uint16_t*)bg->tileset + 49 (ty & (tilesize - 1)) * tilesize; 50 51 tile16_loop_t loop = (tile16_loop_t)bg->fill_loop; 52 loop(scanbuf, tileset_y_offs, tx0, tx1); 53 }