Merge pull request #9199 from Robyt3/Client-Font-Atlas-Cleanup

More efficient glyph uploading, fix crash with very large glyphs and font sizes, refactoring
This commit is contained in:
Dennis Felsing 2024-11-03 21:52:25 +00:00 committed by GitHub
commit 241e8be4a5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 41 additions and 40 deletions

View file

@ -484,7 +484,7 @@ bool CGraphics_Threaded::UnloadTextTextures(CTextureHandle &TextTexture, CTextur
return true; return true;
} }
bool CGraphics_Threaded::UpdateTextTexture(CTextureHandle TextureId, int x, int y, size_t Width, size_t Height, const uint8_t *pData) bool CGraphics_Threaded::UpdateTextTexture(CTextureHandle TextureId, int x, int y, size_t Width, size_t Height, uint8_t *pData, bool IsMovedPointer)
{ {
CCommandBuffer::SCommand_TextTexture_Update Cmd; CCommandBuffer::SCommand_TextTexture_Update Cmd;
Cmd.m_Slot = TextureId.Id(); Cmd.m_Slot = TextureId.Id();
@ -493,10 +493,17 @@ bool CGraphics_Threaded::UpdateTextTexture(CTextureHandle TextureId, int x, int
Cmd.m_Width = Width; Cmd.m_Width = Width;
Cmd.m_Height = Height; Cmd.m_Height = Height;
if(IsMovedPointer)
{
Cmd.m_pData = pData;
}
else
{
const size_t MemSize = Width * Height; const size_t MemSize = Width * Height;
uint8_t *pTmpData = static_cast<uint8_t *>(malloc(MemSize)); uint8_t *pTmpData = static_cast<uint8_t *>(malloc(MemSize));
mem_copy(pTmpData, pData, MemSize); mem_copy(pTmpData, pData, MemSize);
Cmd.m_pData = pTmpData; Cmd.m_pData = pTmpData;
}
AddCmd(Cmd); AddCmd(Cmd);
return true; return true;

View file

@ -950,7 +950,7 @@ public:
bool LoadTextTextures(size_t Width, size_t Height, CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture, uint8_t *pTextData, uint8_t *pTextOutlineData) override; bool LoadTextTextures(size_t Width, size_t Height, CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture, uint8_t *pTextData, uint8_t *pTextOutlineData) override;
bool UnloadTextTextures(CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture) override; bool UnloadTextTextures(CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture) override;
bool UpdateTextTexture(CTextureHandle TextureId, int x, int y, size_t Width, size_t Height, const uint8_t *pData) override; bool UpdateTextTexture(CTextureHandle TextureId, int x, int y, size_t Width, size_t Height, uint8_t *pData, bool IsMovedPointer) override;
CTextureHandle LoadSpriteTexture(const CImageInfo &FromImageInfo, const struct CDataSprite *pSprite) override; CTextureHandle LoadSpriteTexture(const CImageInfo &FromImageInfo, const struct CDataSprite *pSprite) override;

View file

@ -321,9 +321,6 @@ private:
CAtlas m_TextureAtlas; CAtlas m_TextureAtlas;
std::unordered_map<std::tuple<FT_Face, int, int>, SGlyph, SGlyphKeyHash, SGlyphKeyEquals> m_Glyphs; std::unordered_map<std::tuple<FT_Face, int, int>, SGlyph, SGlyphKeyHash, SGlyphKeyEquals> m_Glyphs;
// Data used for rendering glyphs
uint8_t m_aaGlyphData[NUM_FONT_TEXTURES][64 * 1024];
// Font faces // Font faces
FT_Face m_DefaultFace = nullptr; FT_Face m_DefaultFace = nullptr;
FT_Face m_IconFace = nullptr; FT_Face m_IconFace = nullptr;
@ -485,13 +482,13 @@ private:
return OutlineThickness; return OutlineThickness;
} }
void UploadGlyph(int TextureIndex, int PosX, int PosY, size_t Width, size_t Height, const unsigned char *pData) void UploadGlyph(int TextureIndex, int PosX, int PosY, size_t Width, size_t Height, uint8_t *pData)
{ {
for(size_t y = 0; y < Height; ++y) for(size_t y = 0; y < Height; ++y)
{ {
mem_copy(&m_apTextureData[TextureIndex][PosX + ((y + PosY) * m_TextureDimension)], &pData[y * Width], Width); mem_copy(&m_apTextureData[TextureIndex][PosX + ((y + PosY) * m_TextureDimension)], &pData[y * Width], Width);
} }
Graphics()->UpdateTextTexture(m_aTextures[TextureIndex], PosX, PosY, Width, Height, pData); Graphics()->UpdateTextTexture(m_aTextures[TextureIndex], PosX, PosY, Width, Height, pData, true);
} }
bool FitGlyph(size_t Width, size_t Height, int &PosX, int &PosY) bool FitGlyph(size_t Width, size_t Height, int &PosX, int &PosY)
@ -510,6 +507,11 @@ private:
} }
const FT_Bitmap *pBitmap = &Glyph.m_Face->glyph->bitmap; const FT_Bitmap *pBitmap = &Glyph.m_Face->glyph->bitmap;
if(pBitmap->pixel_mode != FT_PIXEL_MODE_GRAY)
{
log_debug("textrender", "Error loading glyph, unsupported pixel mode. Chr=%d GlyphIndex=%u PixelMode=%d", Glyph.m_Chr, Glyph.m_GlyphIndex, pBitmap->pixel_mode);
return false;
}
const unsigned RealWidth = pBitmap->width; const unsigned RealWidth = pBitmap->width;
const unsigned RealHeight = pBitmap->rows; const unsigned RealHeight = pBitmap->rows;
@ -544,23 +546,23 @@ private:
} }
// prepare glyph data // prepare glyph data
mem_zero(m_aaGlyphData[FONT_TEXTURE_FILL], (size_t)Width * Height * sizeof(uint8_t)); const size_t GlyphDataSize = (size_t)Width * Height * sizeof(uint8_t);
uint8_t *pGlyphDataFill = static_cast<uint8_t *>(malloc(GlyphDataSize));
uint8_t *pGlyphDataOutline = static_cast<uint8_t *>(malloc(GlyphDataSize));
mem_zero(pGlyphDataFill, GlyphDataSize);
for(unsigned py = 0; py < pBitmap->rows; ++py) for(unsigned py = 0; py < pBitmap->rows; ++py)
{ {
mem_copy(&m_aaGlyphData[FONT_TEXTURE_FILL][(py + y) * Width + x], &pBitmap->buffer[py * pBitmap->width], pBitmap->width); mem_copy(&pGlyphDataFill[(py + y) * Width + x], &pBitmap->buffer[py * pBitmap->width], pBitmap->width);
} }
Grow(pGlyphDataFill, pGlyphDataOutline, Width, Height, OutlineThickness);
// upload the glyph // upload the glyph
UploadGlyph(FONT_TEXTURE_FILL, X, Y, Width, Height, m_aaGlyphData[FONT_TEXTURE_FILL]); UploadGlyph(FONT_TEXTURE_FILL, X, Y, Width, Height, pGlyphDataFill);
Grow(m_aaGlyphData[FONT_TEXTURE_FILL], m_aaGlyphData[FONT_TEXTURE_OUTLINE], Width, Height, OutlineThickness); UploadGlyph(FONT_TEXTURE_OUTLINE, X, Y, Width, Height, pGlyphDataOutline);
UploadGlyph(FONT_TEXTURE_OUTLINE, X, Y, Width, Height, m_aaGlyphData[FONT_TEXTURE_OUTLINE]);
} }
// set glyph info // set glyph info
{ {
const int BmpWidth = pBitmap->width + x * 2;
const int BmpHeight = pBitmap->rows + y * 2;
Glyph.m_Height = Height; Glyph.m_Height = Height;
Glyph.m_Width = Width; Glyph.m_Width = Width;
Glyph.m_CharHeight = RealHeight; Glyph.m_CharHeight = RealHeight;
@ -571,8 +573,8 @@ private:
Glyph.m_aUVs[0] = X; Glyph.m_aUVs[0] = X;
Glyph.m_aUVs[1] = Y; Glyph.m_aUVs[1] = Y;
Glyph.m_aUVs[2] = Glyph.m_aUVs[0] + BmpWidth; Glyph.m_aUVs[2] = Glyph.m_aUVs[0] + Width;
Glyph.m_aUVs[3] = Glyph.m_aUVs[1] + BmpHeight; Glyph.m_aUVs[3] = Glyph.m_aUVs[1] + Height;
Glyph.m_State = SGlyph::EState::RENDERED; Glyph.m_State = SGlyph::EState::RENDERED;
} }
@ -694,7 +696,7 @@ public:
for(size_t TextureIndex = 0; TextureIndex < NUM_FONT_TEXTURES; ++TextureIndex) for(size_t TextureIndex = 0; TextureIndex < NUM_FONT_TEXTURES; ++TextureIndex)
{ {
mem_zero(m_apTextureData[TextureIndex], m_TextureDimension * m_TextureDimension * sizeof(uint8_t)); mem_zero(m_apTextureData[TextureIndex], m_TextureDimension * m_TextureDimension * sizeof(uint8_t));
Graphics()->UpdateTextTexture(m_aTextures[TextureIndex], 0, 0, m_TextureDimension, m_TextureDimension, m_apTextureData[TextureIndex]); Graphics()->UpdateTextTexture(m_aTextures[TextureIndex], 0, 0, m_TextureDimension, m_TextureDimension, m_apTextureData[TextureIndex], false);
} }
m_TextureAtlas.Clear(m_TextureDimension); m_TextureAtlas.Clear(m_TextureDimension);
@ -791,13 +793,12 @@ public:
} }
const FT_Bitmap *pBitmap = &Face->glyph->bitmap; const FT_Bitmap *pBitmap = &Face->glyph->bitmap;
if(pBitmap->pixel_mode != FT_PIXEL_MODE_GRAY)
// prepare glyph data {
const size_t GlyphDataSize = (size_t)pBitmap->width * pBitmap->rows * sizeof(uint8_t); log_debug("textrender", "Error loading glyph, unsupported pixel mode. Chr=%d GlyphIndex=%u PixelMode=%d", NextCharacter, GlyphIndex, pBitmap->pixel_mode);
if(pBitmap->pixel_mode == FT_PIXEL_MODE_GRAY) pCurrent = pTmp;
mem_copy(m_aaGlyphData[FONT_TEXTURE_FILL], pBitmap->buffer, GlyphDataSize); continue;
else }
mem_zero(m_aaGlyphData[FONT_TEXTURE_FILL], GlyphDataSize);
for(unsigned OffY = 0; OffY < pBitmap->rows; ++OffY) for(unsigned OffY = 0; OffY < pBitmap->rows; ++OffY)
{ {
@ -806,18 +807,11 @@ public:
const int ImgOffX = clamp(x + OffX + WidthLastChars, x, (x + TexSubWidth) - 1); const int ImgOffX = clamp(x + OffX + WidthLastChars, x, (x + TexSubWidth) - 1);
const int ImgOffY = clamp(y + OffY, y, (y + TexSubHeight) - 1); const int ImgOffY = clamp(y + OffY, y, (y + TexSubHeight) - 1);
const size_t ImageOffset = ImgOffY * (TextImage.m_Width * PixelSize) + ImgOffX * PixelSize; const size_t ImageOffset = ImgOffY * (TextImage.m_Width * PixelSize) + ImgOffX * PixelSize;
const size_t GlyphOffset = OffY * pBitmap->width + OffX; for(size_t i = 0; i < PixelSize - 1; ++i)
for(size_t i = 0; i < PixelSize; ++i)
{ {
if(i != PixelSize - 1) TextImage.m_pData[ImageOffset + i] = 255;
{
*(TextImage.m_pData + ImageOffset + i) = 255;
}
else
{
*(TextImage.m_pData + ImageOffset + i) = *(m_aaGlyphData[FONT_TEXTURE_FILL] + GlyphOffset);
}
} }
TextImage.m_pData[ImageOffset + PixelSize - 1] = pBitmap->buffer[OffY * pBitmap->width + OffX];
} }
} }

View file

@ -284,7 +284,7 @@ public:
// pTextData & pTextOutlineData are automatically free'd // pTextData & pTextOutlineData are automatically free'd
virtual bool LoadTextTextures(size_t Width, size_t Height, CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture, uint8_t *pTextData, uint8_t *pTextOutlineData) = 0; virtual bool LoadTextTextures(size_t Width, size_t Height, CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture, uint8_t *pTextData, uint8_t *pTextOutlineData) = 0;
virtual bool UnloadTextTextures(CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture) = 0; virtual bool UnloadTextTextures(CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture) = 0;
virtual bool UpdateTextTexture(CTextureHandle TextureId, int x, int y, size_t Width, size_t Height, const uint8_t *pData) = 0; virtual bool UpdateTextTexture(CTextureHandle TextureId, int x, int y, size_t Width, size_t Height, uint8_t *pData, bool IsMovedPointer) = 0;
virtual CTextureHandle LoadSpriteTexture(const CImageInfo &FromImageInfo, const struct CDataSprite *pSprite) = 0; virtual CTextureHandle LoadSpriteTexture(const CImageInfo &FromImageInfo, const struct CDataSprite *pSprite) = 0;