-
-
Notifications
You must be signed in to change notification settings - Fork 35
Improve the performance of text rendering #53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
TheGag96
wants to merge
4
commits into
devkitPro:master
Choose a base branch
from
TheGag96:faster-text
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
212ba7c
Create a cache around `fontCalcGlyphPos` for ASCII characters
TheGag96 116f09e
Improve text rendering performance again by treating font sheets as c…
TheGag96 52f0cbc
fixup! Create a cache around `fontCalcGlyphPos` for ASCII characters
TheGag96 716c205
Funnel system font handling into the same codepaths as user fonts, ap…
TheGag96 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,8 @@ | |
| #include "internal.h" | ||
| #include <c2d/font.h> | ||
|
|
||
| C2D_Font_s g_systemFont; | ||
|
|
||
| C2D_Font C2D_FontLoad(const char* filename) | ||
| { | ||
| FILE* f = fopen(filename, "rb"); | ||
|
|
@@ -18,38 +20,72 @@ static inline C2D_Font C2Di_FontAlloc(void) | |
| return (C2D_Font)malloc(sizeof(struct C2D_Font_s)); | ||
| } | ||
|
|
||
| static void fillSheet(C3D_Tex *tex, void *data, TGLP_s *glyphInfo) | ||
| { | ||
| tex->data = data; | ||
| tex->fmt = glyphInfo->sheetFmt; | ||
| tex->size = glyphInfo->sheetSize; | ||
| tex->width = glyphInfo->sheetWidth; | ||
| tex->height = glyphInfo->sheetHeight; | ||
| tex->param = GPU_TEXTURE_MAG_FILTER(GPU_LINEAR) | GPU_TEXTURE_MIN_FILTER(GPU_LINEAR) | ||
| | GPU_TEXTURE_WRAP_S(GPU_CLAMP_TO_EDGE) | GPU_TEXTURE_WRAP_T(GPU_CLAMP_TO_EDGE); | ||
| tex->border = 0; | ||
| tex->lodParam = 0; | ||
| } | ||
|
|
||
| static C2D_Font C2Di_PostLoadFont(C2D_Font font) | ||
| { | ||
| if (!font->cfnt) | ||
| { | ||
| free(font); | ||
| font = NULL; | ||
| } else | ||
| } | ||
| else | ||
| { | ||
| fontFixPointers(font->cfnt); | ||
| if (font->cfnt != fontGetSystemFont()) | ||
| { | ||
| fontFixPointers(font->cfnt); | ||
| } | ||
|
|
||
| TGLP_s* glyphInfo = font->cfnt->finf.tglp; | ||
| font->glyphSheets = malloc(sizeof(C3D_Tex)*glyphInfo->nSheets); | ||
| font->textScale = 30.0f / glyphInfo->cellHeight; | ||
|
|
||
| // The way TGLP_s is set up, all of a font's texture sheets are adjacent in memory and have the same size. We can | ||
| // reinterpet the memory to describe a smaller set of much taller textures if we'd like. If we choose the right size, | ||
| // we can get all of the ASCII glyphs under a single texture, which will massively improve performance by reducing | ||
| // texture swaps within a piece of all-English text down to 0! We don't need any extra linear allocating to do this! | ||
| // Let's combine as many sheets as it takes to get to a big sheet height of 1024, which is the maximum height a | ||
| // texture can have. | ||
| font->sheetsPerBigSheet = 1024U / glyphInfo->sheetHeight; | ||
| u32 numSheetsBig = glyphInfo->nSheets / font->sheetsPerBigSheet; | ||
| u32 numSheetsSmall = glyphInfo->nSheets % font->sheetsPerBigSheet; | ||
| u32 numSheetsTotal = numSheetsBig + numSheetsSmall; | ||
| font->numSheetsCombined = glyphInfo->nSheets - numSheetsSmall; | ||
|
|
||
| font->glyphSheets = malloc(sizeof(C3D_Tex)*numSheetsTotal); | ||
| if (!font->glyphSheets) | ||
| { | ||
| C2D_FontFree(font); | ||
| return NULL; | ||
| } | ||
|
|
||
| int i; | ||
| for (i = 0; i < glyphInfo->nSheets; i++) | ||
| memset(font->glyphSheets, 0, sizeof(sizeof(C3D_Tex)*numSheetsTotal)); | ||
| for (u32 i = 0; i < numSheetsBig; i++) | ||
| { | ||
| C3D_Tex* tex = &font->glyphSheets[i]; | ||
| tex->data = &glyphInfo->sheetData[glyphInfo->sheetSize*i]; | ||
| tex->fmt = glyphInfo->sheetFmt; | ||
| tex->size = glyphInfo->sheetSize; | ||
| tex->width = glyphInfo->sheetWidth; | ||
| tex->height = glyphInfo->sheetHeight; | ||
| tex->param = GPU_TEXTURE_MAG_FILTER(GPU_LINEAR) | GPU_TEXTURE_MIN_FILTER(GPU_LINEAR) | ||
| | GPU_TEXTURE_WRAP_S(GPU_CLAMP_TO_BORDER) | GPU_TEXTURE_WRAP_T(GPU_CLAMP_TO_BORDER); | ||
| tex->border = 0; | ||
| tex->lodParam = 0; | ||
| fillSheet(tex, fontGetGlyphSheetTex(font->cfnt, i * font->sheetsPerBigSheet), glyphInfo); | ||
| tex->height = (uint16_t) (tex->height * font->sheetsPerBigSheet); | ||
| tex->size = tex->size * font->sheetsPerBigSheet; | ||
| } | ||
|
|
||
| for (u32 i = 0; i < numSheetsSmall; i++) | ||
| { | ||
| fillSheet(&font->glyphSheets[numSheetsBig + i], fontGetGlyphSheetTex(font->cfnt, numSheetsBig * font->sheetsPerBigSheet + i), glyphInfo); | ||
| } | ||
|
|
||
| for (u32 i = 0; i < NUM_ASCII_CHARACTERS; i++) | ||
| { | ||
| // This will readjust glyph UVs to account for being a part of the combined texture. | ||
| C2D_FontCalcGlyphPos(NULL, &font->asciiCache[i], fontGlyphIndexFromCodePoint(font->cfnt, i), 0, 1.0, 1.0); | ||
| } | ||
| } | ||
| return font; | ||
|
|
@@ -151,6 +187,13 @@ static C2D_Font C2Di_FontLoadFromArchive(u64 tid, const char* path) | |
| return C2Di_PostLoadFont(font); | ||
| } | ||
|
|
||
| C2D_Font C2Di_LoadSystemFont(void) | ||
| { | ||
| g_systemFont.cfnt = fontGetSystemFont(); | ||
| C2Di_PostLoadFont(&g_systemFont); | ||
| return &g_systemFont; | ||
| } | ||
|
|
||
| static unsigned C2Di_RegionToFontIndex(CFG_Region region) | ||
| { | ||
| switch (region) | ||
|
|
@@ -196,7 +239,7 @@ C2D_Font C2D_FontLoadSystem(CFG_Region region) | |
|
|
||
| void C2D_FontFree(C2D_Font font) | ||
| { | ||
| if (font) | ||
| if (font && font != &g_systemFont) | ||
| { | ||
| if (font->cfnt) | ||
| linearFree(font->cfnt); | ||
|
|
@@ -206,7 +249,7 @@ void C2D_FontFree(C2D_Font font) | |
|
|
||
| void C2D_FontSetFilter(C2D_Font font, GPU_TEXTURE_FILTER_PARAM magFilter, GPU_TEXTURE_FILTER_PARAM minFilter) | ||
| { | ||
| if (!font) | ||
| if (!font || font == &g_systemFont) | ||
| return; | ||
|
|
||
| TGLP_s* glyphInfo = font->cfnt->finf.tglp; | ||
|
|
@@ -221,32 +264,53 @@ void C2D_FontSetFilter(C2D_Font font, GPU_TEXTURE_FILTER_PARAM magFilter, GPU_TE | |
|
|
||
| int C2D_FontGlyphIndexFromCodePoint(C2D_Font font, u32 codepoint) | ||
| { | ||
| if (!font) | ||
| return fontGlyphIndexFromCodePoint(fontGetSystemFont(), codepoint); | ||
| else | ||
| return fontGlyphIndexFromCodePoint(font->cfnt, codepoint); | ||
| if (!font) font = &g_systemFont; | ||
| return fontGlyphIndexFromCodePoint(font->cfnt, codepoint); | ||
| } | ||
|
|
||
| charWidthInfo_s* C2D_FontGetCharWidthInfo(C2D_Font font, int glyphIndex) | ||
| { | ||
| if (!font) | ||
| return fontGetCharWidthInfo(fontGetSystemFont(), glyphIndex); | ||
| else | ||
| return fontGetCharWidthInfo(font->cfnt, glyphIndex); | ||
| if (!font) font = &g_systemFont; | ||
| return fontGetCharWidthInfo(font->cfnt, glyphIndex); | ||
| } | ||
|
|
||
| void C2D_FontCalcGlyphPos(C2D_Font font, fontGlyphPos_s* out, int glyphIndex, u32 flags, float scaleX, float scaleY) | ||
| { | ||
| if (!font) | ||
| fontCalcGlyphPos(out, fontGetSystemFont(), glyphIndex, flags, scaleX, scaleY); | ||
| if (!font) font = &g_systemFont; | ||
| fontCalcGlyphPos(out, font->cfnt, glyphIndex, flags, scaleX, scaleY); | ||
|
|
||
| if (out->sheetIndex < font->numSheetsCombined) | ||
| { | ||
| u32 indexWithinBigSheet = out->sheetIndex % font->sheetsPerBigSheet; | ||
| out->sheetIndex /= font->sheetsPerBigSheet; | ||
|
|
||
| // Readjust glyph UVs to account for being a part of the combined texture. | ||
| out->texcoord.top = (out->texcoord.top + (font->sheetsPerBigSheet - indexWithinBigSheet - 1)) / (float) font->sheetsPerBigSheet; | ||
| out->texcoord.bottom = (out->texcoord.bottom + (font->sheetsPerBigSheet - indexWithinBigSheet - 1)) / (float) font->sheetsPerBigSheet; | ||
| } | ||
| else | ||
| { | ||
| out->sheetIndex = out->sheetIndex - font->numSheetsCombined + font->numSheetsCombined / font->sheetsPerBigSheet; | ||
| } | ||
| } | ||
|
|
||
| void C2D_FontCalcGlyphPosFromCodePoint(C2D_Font font, fontGlyphPos_s* out, u32 codepoint, u32 flags, float scaleX, float scaleY) | ||
| { | ||
| if (!font) font = &g_systemFont; | ||
|
|
||
| // Building glyph positions is pretty expensive, but we could just store the results for plain ASCII. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The indentation style is inconsistent. |
||
| if (codepoint < NUM_ASCII_CHARACTERS && flags == 0 && scaleX == 1 && scaleY == 1) | ||
| { | ||
| *out = font->asciiCache[codepoint]; | ||
| } | ||
| else | ||
| fontCalcGlyphPos(out, font->cfnt, glyphIndex, flags, scaleX, scaleY); | ||
| { | ||
| C2D_FontCalcGlyphPos(font, out, C2D_FontGlyphIndexFromCodePoint(font, codepoint), 0, 1.0f, 1.0f); | ||
| } | ||
| } | ||
|
|
||
| FINF_s* C2D_FontGetInfo(C2D_Font font) | ||
| { | ||
| if (!font) | ||
| return fontGetInfo(NULL); | ||
| else | ||
| return fontGetInfo(font->cfnt); | ||
| if (!font) font = &g_systemFont; | ||
| return fontGetInfo(font->cfnt); | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The indentation style is inconsistent here.