Alchemy
Loading...
Searching...
No Matches

vram_cache.c

Go to the documentation of this file.
1/// @file
2/// The sprite VRAM cache: blocks, entries and loading pictures.
3/// Part of runtime.c, the runtime object, compiled only through it.
4
6
7// The sprite VRAM cache. Sprite tile memory (from 0x06010000) is split into
8// 512 blocks of 64 bytes, and gResourceBlockOwners records which of the 96
9// cache entries owns each block. An entry whose offset is 0xffff is free; one
10// whose size is 16 or less holds no VRAM.
11
12/// Finds the first run of free blocks that holds `size` bytes and gives it to
13/// entry `id`, writing `id` into gResourceBlockOwners for each block. Called by
14/// VramCache_Load. Returns its byte offset in sprite VRAM, or -1 when no run
15/// is long enough.
17 u32 blocks;
18 s32 ret;
19 s32 pos;
20 u32 end;
21 u32 i;
22
23 blocks = size / VRAM_BLOCK_BYTES;
24 if (id >= VRAM_CACHE_ENTRY_COUNT) {
25 return -1;
26 }
27 pos = 0;
28 for (;;) {
29 ret = -1;
30 if (pos >= VRAM_BLOCK_COUNT) {
31 return ret;
32 }
34 ret = pos;
35 end = blocks + ret;
36 while (pos < end) {
38 goto occupied;
39 }
40 pos++;
41 }
42 for (i = 0; i < blocks; i++) {
43 gResourceBlockOwners[ret + i] = id;
44 }
45 break;
46 }
47 occupied:
48 // Skip an owned block by its owner's whole size
50 }
51 ret *= VRAM_BLOCK_BYTES;
52 return ret;
53}
54
55/// Returns the length, in blocks, of the longest run of free blocks. Nothing
56/// in ☀️ calls it.
58 s32 run = 0;
59 u8 *owner = gResourceBlockOwners;
60 s32 longestRun = 0;
61 s32 remaining = VRAM_BLOCK_COUNT;
62
63 do {
64 if (*owner++ != VRAM_BLOCK_OWNER_FREE) {
65 run = 0;
66 } else {
67 run++;
68 if (longestRun < run)
69 longestRun = run;
70 }
71 remaining--;
72 } while (remaining != 0);
73 return longestRun;
74}
75
76/// Frees every block entry `id` owns in gResourceBlockOwners. Called by
77/// Resource_ResetEntry and VramCache_ReleaseVram. Returns -1 when it freed any
78/// (or `id` is out of range) and 0 when the entry owned none.
80 s32 cleared = 0;
81 s32 remaining;
82 u8 *owner;
83 u8 empty;
84
85 if ((u32)id >= VRAM_CACHE_ENTRY_COUNT)
86 return -1;
89 remaining = VRAM_BLOCK_COUNT;
90 do {
91 if (*owner == id) {
92 *owner = empty;
93 cleared++;
94 }
95 remaining--;
96 owner++;
97 } while (remaining != 0);
98 if (cleared != 0)
99 return -1;
100 return 0;
101}
102
103/// Frees cache entry `no`: its blocks go back and the entry is marked free
104/// (offset 0xffff). Called throughout the game when a sprite's picture is no
105/// longer shown.
107 struct VramBlockCacheEntry *entry = &gVramBlockCache[no];
108
109 if (no >= VRAM_CACHE_ENTRY_COUNT)
110 return -1;
111 if (entry->offset != VRAM_CACHE_OFFSET_FREE) {
114 entry->size = 0;
115 }
116 return 0;
117}
118
119/// Gives back entry `no`'s blocks but keeps the entry taken, with size 1, so
120/// a later VramCache_Load can refill it. Called by the field sprites and
121/// cameras.
123 struct VramBlockCacheEntry *entry = &gVramBlockCache[no];
124
125 if (no >= VRAM_CACHE_ENTRY_COUNT)
126 return -1;
127 if (entry->size > 16) {
128 s32 one;
129
131 one = 1;
132 entry->size = one;
133 }
134 return 0;
135}
136
137/// Gives cache entry `no` `size` bytes of sprite VRAM and copies `src` there.
138/// An entry that already holds VRAM of the same size keeps it. A null `src`
139/// copies nothing and (void *)-1 clears the memory. Writes the entry's offset
140/// and size into gVramBlockCache. Called throughout the game to load sprite
141/// pictures. Returns the first sprite tile number (32-byte units), or 0 when
142/// there was no room.
143s32 VramCache_Load(u32 no, u32 size, const void *src) {
144 struct VramBlockCacheEntry *entry;
145 s32 offset;
146 void *dst;
147
148 entry = &gVramBlockCache[no];
149 if (no >= VRAM_CACHE_ENTRY_COUNT)
150 return 0;
151 if (size > 8192)
152 return 0;
153 // A same-size upload keeps its existing VRAM run.
154 if (entry->size > 16) {
155 if (entry->size != size) {
158 } else {
159 offset = entry->offset;
160 }
161 } else {
163 }
164
165 if (offset != -1) {
166 // Commit the allocation before copying, clearing or leaving its pixels.
167 dst = (void *)(OBJ_VRAM0 + offset);
168 entry->size = size;
169 entry->offset = offset;
170 if (src != 0) {
171 if (src == (const void *)-1) {
173 } else {
174 Dma_Set(src, dst, DMA_COPY_WORDS(size >> 2), REG_DMA3);
175 }
176 }
177 return (u32)offset >> 5;
178 }
179 return 0;
180}
181
182/// Frees every block and every cache entry. Called by System_Initialize,
183/// Game_ResetForNewGame and the debug modes that start over.
184void VramCache_Reset(void) {
185 u32 limit = VRAM_BLOCK_COUNT - 1;
187 u32 n = 0;
189
190 do {
191 *p++ = empty;
192 n++;
193 } while (n <= limit);
194
195 {
196 struct VramBlockCacheEntry *entry = gVramBlockCache;
197
198 n = 0;
199 do {
201 entry->size = 0;
202 entry++;
203 n++;
204 } while (n < VRAM_CACHE_ENTRY_COUNT);
205 }
206}
207
208/// Returns the number of the first free cache entry, or VRAM_CACHE_ENTRY_COUNT
209/// when all are taken. Called before VramCache_Load by code that keeps the
210/// entry number.
213 s32 no;
214 struct VramBlockCacheEntry *entry = gVramBlockCache;
215
216 for (no = 0; no < VRAM_CACHE_ENTRY_COUNT; no++, entry++) {
217 if (entry->offset == VRAM_CACHE_OFFSET_FREE) {
218 ret = no;
219 break;
220 }
221 }
222 return ret;
223}
224
225/// Takes a free cache entry, gives it `size` bytes of sprite VRAM and returns
226/// its number. Called by the battle prompts and the menus' command rows.
228 s32 no;
229
231 VramCache_Load(no, size, 0);
232 return no;
233}
234
235/// Copies `src` again into entry `no`'s VRAM, keeping its size. Called by
236/// code that redraws a sprite picture in place, such as the battle prompts.
237/// Returns the first sprite tile number.
239 return VramCache_Load(no, gVramBlockCache[no].size, (const void *)src);
240}
static __inline__ void Dma_Set(const volatile void *source, volatile void *destination, u32 control, volatile u32 *channel)
Starts a DMA transfer: stores the source, destination and control words into channel's registers with...
Definition dma.h:62
#define OBJ_VRAM0
Sprite tile memory, as pret names it: the 32 KB from 0x06010000.
Definition io_reg.h:170
#define REG_DMA3
Definition io_reg.h:153
#define DMA_COPY_WORDS(n)
Definition io_reg.h:226
static s32 Iwram_ClearWords(void *destination, s32 size)
Definition iwram_call.h:55
What every part of the runtime object shares: its includes and the library call two parts make.
A sprite slot of the VRAM cache: the size of its block and where the block starts in OBJ VRAM.
Definition vram_tab.h:23
u16 offset
bytes from the start of OBJ VRAM
Definition vram_tab.h:25
signed int s32
Definition types.h:14
unsigned int u32
Definition types.h:15
unsigned char u8
Definition types.h:11
s32 VramCache_FreeBlocks(s32 id)
Frees every block entry id owns in gResourceBlockOwners.
Definition vram_cache.c:79
void VramCache_Reset(void)
Frees every block and every cache entry.
Definition vram_cache.c:184
s32 VramCache_AllocEntry(s32 size)
Takes a free cache entry, gives it size bytes of sprite VRAM and returns its number.
Definition vram_cache.c:227
s32 VramCache_Reload(s32 no, s32 src)
Copies src again into entry no's VRAM, keeping its size.
Definition vram_cache.c:238
s32 VramCache_GetLongestFreeRun(void)
Returns the length, in blocks, of the longest run of free blocks.
Definition vram_cache.c:57
s32 VramCache_ReleaseVram(u32 no)
Gives back entry no's blocks but keeps the entry taken, with size 1, so a later VramCache_Load can re...
Definition vram_cache.c:122
s32 VramCache_AllocateBlocks(u32 id, u32 size)
Finds the first run of free blocks that holds size bytes and gives it to entry id,...
Definition vram_cache.c:16
s32 Resource_ResetEntry(u32 no)
Frees cache entry no: its blocks go back and the entry is marked free (offset 0xffff).
Definition vram_cache.c:106
s32 Resource_FindFreeEntry(void)
Returns the number of the first free cache entry, or VRAM_CACHE_ENTRY_COUNT when all are taken.
Definition vram_cache.c:211
s32 VramCache_Load(u32 no, u32 size, const void *src)
Gives cache entry no size bytes of sprite VRAM and copies src there.
Definition vram_cache.c:143
struct VramBlockCacheEntry gVramBlockCache[]
u8 gResourceBlockOwners[VRAM_BLOCK_COUNT]
@ VRAM_BLOCK_BYTES
Definition vram_tab.h:14
@ VRAM_CACHE_ENTRY_COUNT
Definition vram_tab.h:12
@ VRAM_CACHE_OFFSET_FREE
Definition vram_tab.h:16
@ VRAM_BLOCK_COUNT
Definition vram_tab.h:13
@ VRAM_BLOCK_OWNER_FREE
Definition vram_tab.h:15