Skip to content

Commit 8dfcdfa

Browse files
committed
imageview: Optimize RAM usage in DS mode by adding LRU cache for font tiles
1 parent 931a582 commit 8dfcdfa

File tree

3 files changed

+82
-61
lines changed

3 files changed

+82
-61
lines changed

imageview/arm9/source/graphics/FontGraphic.cpp

Lines changed: 69 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
#include "common/tonccpy.h"
44

5-
u8 *FontGraphic::lastUsedLoc = (u8*)0x08000000;
6-
75
u8 FontGraphic::textBuf[256 * 192];
86

97
std::map<char16_t, std::array<char16_t, 3>> FontGraphic::arabicPresentationForms = {
@@ -90,19 +88,15 @@ char16_t FontGraphic::arabicForm(char16_t current, char16_t prev, char16_t next)
9088
return current;
9189
}
9290

93-
FontGraphic::FontGraphic(const std::vector<std::string> &paths, bool useExpansionPak) : useExpansionPak(useExpansionPak) {
94-
FILE *file = nullptr;
91+
FontGraphic::FontGraphic(const std::vector<std::string> &paths, const bool set_useTileCache) {
9592
for (const auto &path : paths) {
9693
file = fopen(path.c_str(), "rb");
9794
if (file)
9895
break;
9996
}
10097

98+
useTileCache = set_useTileCache;
10199
if (file) {
102-
if (useExpansionPak && *(u16*)(0x020000C0) == 0 && lastUsedLoc == (u8*)0x08000000) {
103-
lastUsedLoc += 0x01000000;
104-
}
105-
106100
// Get file size
107101
fseek(file, 0, SEEK_END);
108102
u32 fileSize = ftell(file);
@@ -121,14 +115,8 @@ FontGraphic::FontGraphic(const std::vector<std::string> &paths, bool useExpansio
121115
// Load character glyphs
122116
tileAmount = (chunkSize - 0x10) / tileSize;
123117
fseek(file, 4, SEEK_CUR);
124-
if (useExpansionPak) {
125-
fontTiles = lastUsedLoc;
126-
lastUsedLoc += tileSize * tileAmount;
127-
128-
u8 *buf = new u8[tileSize * tileAmount];
129-
fread(buf, tileSize, tileAmount, file);
130-
tonccpy(fontTiles, buf, tileSize * tileAmount);
131-
delete[] buf;
118+
if (useTileCache) {
119+
fontTiles = new u8[tileSize * (tileAmount>tileCacheCount ? tileCacheCount : tileAmount)];
132120
} else {
133121
fontTiles = new u8[tileSize * tileAmount];
134122
fread(fontTiles, tileSize, tileAmount, file);
@@ -141,32 +129,17 @@ FontGraphic::FontGraphic(const std::vector<std::string> &paths, bool useExpansio
141129
fseek(file, locHDWC-4, SEEK_SET);
142130
fread(&chunkSize, 4, 1, file);
143131
fseek(file, 8, SEEK_CUR);
144-
if (useExpansionPak) {
145-
fontWidths = lastUsedLoc;
146-
lastUsedLoc += 3 * tileAmount;
147-
148-
u8 *buf = new u8[3 * tileAmount];
149-
fread(buf, 3, tileAmount, file);
150-
tonccpy(fontWidths, buf, 3 * tileAmount);
151-
delete[] buf;
152-
} else {
153-
fontWidths = new u8[3 * tileAmount];
154-
fread(fontWidths, 3, tileAmount, file);
155-
}
132+
fontWidths = new u8[3 * tileAmount];
133+
fread(fontWidths, 3, tileAmount, file);
156134

157135
// Load character maps
158-
if (useExpansionPak) {
159-
fontMap = (u16*)lastUsedLoc;
160-
lastUsedLoc += tileAmount * sizeof(u16);
161-
} else {
162-
fontMap = new u16[tileAmount];
163-
}
136+
fontMap = new u16[tileAmount];
164137

165138
fseek(file, 0x28, SEEK_SET);
166139
u32 locPAMC, mapType;
167140
fread(&locPAMC, 4, 1, file);
168141

169-
while (locPAMC < fileSize) {
142+
while (locPAMC && locPAMC < fileSize) {
170143
u16 firstChar, lastChar;
171144
fseek(file, locPAMC, SEEK_SET);
172145
fread(&firstChar, 2, 1, file);
@@ -202,22 +175,20 @@ FontGraphic::FontGraphic(const std::vector<std::string> &paths, bool useExpansio
202175
}
203176
}
204177
}
205-
fclose(file);
206178
questionMark = getCharIndex(0xFFFD);
207179
if (questionMark == 0)
208180
questionMark = getCharIndex('?');
209181
}
210182
}
211183

212184
FontGraphic::~FontGraphic(void) {
213-
if (!useExpansionPak) {
214-
if (fontTiles)
215-
delete[] fontTiles;
216-
if (fontWidths)
217-
delete[] fontWidths;
218-
if (fontMap)
219-
delete[] fontMap;
220-
}
185+
fclose(file);
186+
if (fontTiles)
187+
delete[] fontTiles;
188+
if (fontWidths)
189+
delete[] fontWidths;
190+
if (fontMap)
191+
delete[] fontMap;
221192
}
222193

223194
u16 FontGraphic::getCharIndex(char16_t c) {
@@ -430,14 +401,60 @@ ITCM_CODE void FontGraphic::print(int x, int y, bool top, std::u16string_view te
430401
index = getCharIndex(*it);
431402
}
432403

433-
// Don't draw off screen chars
434-
if (x >= 0 && x + fontWidths[(index * 3) + 2] < 256 && y >= 0 && y + tileHeight < 192) {
435-
u8 *dst = textBuf + x + fontWidths[(index * 3)];
436-
for (int i = 0; i < tileHeight; i++) {
437-
for (int j = 0; j < tileWidth; j++) {
438-
u8 px = fontTiles[(index * tileSize) + (i * tileWidth + j) / 4] >> ((3 - ((i * tileWidth + j) % 4)) * 2) & 3;
439-
if (px)
440-
dst[(y + i) * 256 + j] = px + 0xF8;
404+
if (useTileCache) {
405+
bool found = false;
406+
bool overwrite = true;
407+
u8 cachePos = 0;
408+
for (u8 i = 0; i < tileCacheCount; i++) {
409+
if (!cacheAllocated[i]) {
410+
indexCache[i] = index;
411+
cachePos = i;
412+
cacheAllocated[i] = true;
413+
overwrite = false;
414+
break;
415+
} else if (indexCache[i] == index) {
416+
cachePos = i;
417+
found = true;
418+
overwrite = false;
419+
break;
420+
}
421+
}
422+
423+
if (overwrite) {
424+
nextCachePos++;
425+
if (nextCachePos == tileCacheCount) {
426+
nextCachePos = 0;
427+
}
428+
cachePos = nextCachePos;
429+
indexCache[cachePos] = index;
430+
}
431+
432+
if (!found && file) {
433+
fseek(file, 0x40+(index * tileSize), SEEK_SET);
434+
fread(fontTiles+(cachePos * tileSize), tileSize, 1, file);
435+
}
436+
437+
// Don't draw off screen chars
438+
if (x >= 0 && x + fontWidths[(index * 3) + 2] < 256 && y >= 0 && y + tileHeight < 192) {
439+
u8 *dst = textBuf + x + fontWidths[(index * 3)];
440+
for (int i = 0; i < tileHeight; i++) {
441+
for (int j = 0; j < tileWidth; j++) {
442+
u8 px = fontTiles[(cachePos * tileSize) + (i * tileWidth + j) / 4] >> ((3 - ((i * tileWidth + j) % 4)) * 2) & 3;
443+
if (px)
444+
dst[(y + i) * 256 + j] = px + 0xF8;
445+
}
446+
}
447+
}
448+
} else {
449+
// Don't draw off screen chars
450+
if (x >= 0 && x + fontWidths[(index * 3) + 2] < 256 && y >= 0 && y + tileHeight < 192) {
451+
u8 *dst = textBuf + x + fontWidths[(index * 3)];
452+
for (int i = 0; i < tileHeight; i++) {
453+
for (int j = 0; j < tileWidth; j++) {
454+
u8 px = fontTiles[(index * tileSize) + (i * tileWidth + j) / 4] >> ((3 - ((i * tileWidth + j) % 4)) * 2) & 3;
455+
if (px)
456+
dst[(y + i) * 256 + j] = px + 0xF8;
457+
}
441458
}
442459
}
443460
}

imageview/arm9/source/graphics/FontGraphic.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#include <string_view>
88
#include <vector>
99

10+
#define tileCacheCount 128
11+
1012
enum class Alignment {
1113
left,
1214
center,
@@ -24,13 +26,15 @@ class FontGraphic {
2426

2527
static char16_t arabicForm(char16_t current, char16_t prev, char16_t next);
2628

27-
static u8 *lastUsedLoc;
28-
29-
bool useExpansionPak = false;
29+
FILE* file = nullptr;
30+
bool useTileCache = false;
3031
u8 tileWidth = 0, tileHeight = 0;
3132
u16 tileSize = 0;
3233
int tileAmount = 0;
3334
u16 questionMark = 0;
35+
u16 indexCache[tileCacheCount] = {0xFFFF};
36+
bool cacheAllocated[tileCacheCount] = {false};
37+
u8 nextCachePos = 0xFF;
3438
u8 *fontTiles = nullptr;
3539
u8 *fontWidths = nullptr;
3640
u16 *fontMap = nullptr;
@@ -42,7 +46,7 @@ class FontGraphic {
4246

4347
static std::u16string utf8to16(std::string_view text);
4448

45-
FontGraphic(const std::vector<std::string> &paths, const bool useExpansionPak);
49+
FontGraphic(const std::vector<std::string> &paths, const bool set_useTileCache);
4650

4751
~FontGraphic(void);
4852

imageview/arm9/source/graphics/fontHandler.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ bool fileExists(std::vector<std::string_view> paths) {
3030
}
3131

3232
void fontInit() {
33-
bool useExpansionPak = (sys().isRegularDS() && ((*(u16*)(0x020000C0) != 0 && *(u16*)(0x020000C0) != 0x5A45) || *(vu16*)(0x08240000) == 1) && (io_dldi_data->ioInterface.features & FEATURE_SLOT_NDS));
33+
// const bool useExpansionPak = (sys().isRegularDS() && ((*(u16*)(0x020000C0) != 0 && *(u16*)(0x020000C0) != 0x5A45) || *(vu16*)(0x08240000) == 1) && (io_dldi_data->ioInterface.features & FEATURE_SLOT_NDS));
34+
const bool useTileCache = (!dsiFeatures() && !sys().dsDebugRam());
3435

3536
// Unload fonts if already loaded
3637
if (smallFont)
@@ -41,13 +42,12 @@ void fontInit() {
4142
// Load font graphics
4243
std::string fontPath = std::string(sys().isRunFromSD() ? "sd:" : "fat:") + "/_nds/TWiLightMenu/extras/fonts/" + ms().font;
4344
std::string defaultPath = std::string(sys().isRunFromSD() ? "sd:" : "fat:") + "/_nds/TWiLightMenu/extras/fonts/Default";
44-
bool dsiFont = dsiFeatures() || sys().dsDebugRam() || useExpansionPak;
45-
smallFont = new FontGraphic({fontPath + (dsiFont ? "/small-dsi.nftr" : "/small-ds.nftr"), fontPath + "/small.nftr", defaultPath + (dsiFont ? "/small-dsi.nftr" : "/small-ds.nftr"), "nitro:/graphics/font/small.nftr"}, useExpansionPak);
45+
smallFont = new FontGraphic({fontPath + "/small-dsi.nftr", fontPath + "/small.nftr", defaultPath + "/small-dsi.nftr", "nitro:/graphics/font/small.nftr"}, useTileCache);
4646
// If custom small font but no custom large font, use small font as large font
47-
if (fileExists({fontPath + (dsiFont ? "/small-dsi.nftr" : "/small-ds.nftr"), fontPath + "/small.nftr"}) && !fileExists({fontPath + (dsiFont ? "/large-dsi.nftr" : "/large-ds.nftr"), fontPath + "/large.nftr"}))
47+
if (fileExists({fontPath + "/small-dsi.nftr", fontPath + "/small.nftr"}) && !fileExists({fontPath + "/large-dsi.nftr", fontPath + "/large.nftr"}))
4848
largeFont = smallFont;
4949
else
50-
largeFont = new FontGraphic({fontPath + (dsiFont ? "/large-dsi.nftr" : "/large-ds.nftr"), fontPath + "/large.nftr", defaultPath + (dsiFont ? "/large-dsi.nftr" : "/large-ds.nftr"), "nitro:/graphics/font/large.nftr"}, useExpansionPak);
50+
largeFont = new FontGraphic({fontPath + "/large-dsi.nftr", fontPath + "/large.nftr", defaultPath + "/large-dsi.nftr", "nitro:/graphics/font/large.nftr"}, useTileCache);
5151

5252
// Load palettes
5353
u16 palette[] = {

0 commit comments

Comments
 (0)