From 16059ab632d2d0e8ebef8dfedbd533b5499bce3d Mon Sep 17 00:00:00 2001 From: Rickey Fehr Date: Tue, 7 Oct 2025 18:41:21 -0700 Subject: [PATCH] Update for PR Readd sprite tracker to not reuse indices check for capacity when returning pool entries Update script for printing memory map --- include/pool.h | 7 ++++--- include/sprite.h | 3 ++- scripts/get_memory_map.sh | 19 +++++++++++++++++-- source/pool.c | 2 +- source/sprite.c | 19 +++++++++++++++++++ 5 files changed, 43 insertions(+), 7 deletions(-) diff --git a/include/pool.h b/include/pool.h index e9cc6e1..ebdba1b 100644 --- a/include/pool.h +++ b/include/pool.h @@ -10,6 +10,7 @@ typedef struct PoolBitmap { u32 *w; u32 nbits; u32 nwords; + u32 cap; } PoolBitmap; void pool_bm_clear_idx(PoolBitmap *bm, int idx); @@ -20,7 +21,6 @@ int pool_bm_get_free_idx(PoolBitmap *bm); { \ PoolBitmap bm; \ type * objects; \ - u32 max_entries; \ } type##Pool; \ type *pool_get_##type(); \ void pool_free_##type(type *obj); \ @@ -33,9 +33,10 @@ int pool_bm_get_free_idx(PoolBitmap *bm); .bm = { \ .w = type##_bitmap_w, \ .nbits = POOL_BITS_PER_WORD, \ - .nwords = sizeof(u32)}, \ + .nwords = sizeof(u32), \ + .cap = capacity, \ + }, \ .objects = type##_storage, \ - .max_entries = capacity, \ }; \ type * pool_get_##type() \ { \ diff --git a/include/sprite.h b/include/sprite.h index dcd2055..18dce69 100644 --- a/include/sprite.h +++ b/include/sprite.h @@ -14,6 +14,7 @@ typedef struct OBJ_ATTR *obj; OBJ_AFFINE *aff; POINT pos; + int idx; } Sprite; // A sprite object is a sprite that is selectable and movable in animation @@ -66,4 +67,4 @@ Sprite* sprite_object_get_sprite(SpriteObject* sprite_object); void sprite_object_set_focus(SpriteObject* sprite_object, bool focus); bool sprite_object_is_focused(SpriteObject* sprite_object); -#endif // SPRITE_H \ No newline at end of file +#endif // SPRITE_H diff --git a/scripts/get_memory_map.sh b/scripts/get_memory_map.sh index 6b0f03a..ed311c1 100755 --- a/scripts/get_memory_map.sh +++ b/scripts/get_memory_map.sh @@ -4,7 +4,7 @@ set -euo pipefail POOL_DEF_FILE='./include/pools.def' ELF_FILE="${1-./build/balatro-gba.elf}" -READELF='/opt/devkitpro/devkitARM/bin/arm-none-eabi-readelf' +READELF="${READELF-/opt/devkitpro/devkitARM/bin/arm-none-eabi-readelf}" TOTAL_BYTES=0 if [ ! -f "$ELF_FILE" ]; then @@ -14,6 +14,13 @@ if [ ! -f "$ELF_FILE" ]; then exit 1 fi +if [ ! -x "$READELF" ]; then + echo "ERROR: \"$READELF\" is not an executable file." + echo "You can override the file location for 'arm-none-eabi-readelf' with the READELF env variable." + echo " e.g. $ READELF=\"/my/custom/location/arm-none-eabi-readelf\" $(basename $0) " + exit 1 +fi + print_line_break() { echo "--------------------------------------------------------------------" } @@ -41,12 +48,20 @@ for name in $(get_pool_names); do sed -E 's@ +@ @g; s@^ @@' | \ tr -d '\n' \ )" + output_bm="$( \ + "$READELF" -sW "$ELF_FILE" | \ + grep -E "${name}_bitmap_w" | \ + grep OBJECT | \ + sed -E 's@ +@ @g; s@^ @@' | \ + tr -d '\n' \ + )" address="$(cut -d ' ' -f 2 <<< $output_pool)" pool_size="$(cut -d ' ' -f 3 <<< $output_pool)" func_size="$(cut -d ' ' -f 3 <<< $output_func)" - bm_size=16 #always gonna be 16, 4 * sizeof(u32) + bm_size="$(cut -d ' ' -f 3 <<< $output_bm)" + #bm_size=16 #always gonna be 16, 4 * sizeof(u32) TOTAL_BYTES=$(( TOTAL_BYTES + pool_size + func_size + bm_size )) diff --git a/source/pool.c b/source/pool.c index 363b715..29ae12c 100644 --- a/source/pool.c +++ b/source/pool.c @@ -28,7 +28,7 @@ int pool_bm_get_free_idx(PoolBitmap *bm) int bit = __builtin_ctz(inv); bm->w[i] |= ((u32)1 << bit); int idx = i * POOL_BITS_PER_WORD + bit; - return idx; + return (idx < bm->cap) ? idx : -1; } } diff --git a/source/sprite.c b/source/sprite.c index 617a079..355a973 100644 --- a/source/sprite.c +++ b/source/sprite.c @@ -15,11 +15,23 @@ OBJ_ATTR obj_buffer[MAX_SPRITES]; OBJ_AFFINE *obj_aff_buffer = (OBJ_AFFINE*)obj_buffer; +typedef struct +{ + bool used; + Sprite* p_sprite; +} _UsedSprite; + static bool free_affines[MAX_AFFINES] = {false}; +static _UsedSprite free_sprites[MAX_SPRITES] = {{0}}; // Sprite methods Sprite *sprite_new(u16 a0, u16 a1, u32 tid, u32 pb, int sprite_index) { + if(free_sprites[sprite_index].used) + { + return free_sprites[sprite_index].p_sprite; + } + Sprite* sprite = POOL_GET(Sprite); sprite->obj = NULL; @@ -41,6 +53,7 @@ Sprite *sprite_new(u16 a0, u16 a1, u32 tid, u32 pb, int sprite_index) if (aff_index == MAX_AFFINES) { + POOL_FREE(Sprite, sprite); return NULL; } @@ -57,6 +70,9 @@ Sprite *sprite_new(u16 a0, u16 a1, u32 tid, u32 pb, int sprite_index) obj_set_attr(sprite->obj, a0, a1, ATTR2_PALBANK(pb) | tid); } + free_sprites[sprite_index].used = true; + free_sprites[sprite_index].p_sprite = sprite; + sprite->idx = sprite_index; return sprite; } @@ -72,6 +88,9 @@ void sprite_destroy(Sprite **sprite) free_affines[(*sprite)->aff - obj_aff_buffer] = false; } + free_sprites[(*sprite)->idx].used = false; + free_sprites[(*sprite)->idx].p_sprite = NULL; + POOL_FREE(Sprite, *sprite); *sprite = NULL;