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;
}
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;
Cmd.m_Slot = TextureId.Id();
@ -493,10 +493,17 @@ bool CGraphics_Threaded::UpdateTextTexture(CTextureHandle TextureId, int x, int
Cmd.m_Width = Width;
Cmd.m_Height = Height;
const size_t MemSize = Width * Height;
uint8_t *pTmpData = static_cast<uint8_t *>(malloc(MemSize));
mem_copy(pTmpData, pData, MemSize);
Cmd.m_pData = pTmpData;
if(IsMovedPointer)
{
Cmd.m_pData = pData;
}
else
{
const size_t MemSize = Width * Height;
uint8_t *pTmpData = static_cast<uint8_t *>(malloc(MemSize));
mem_copy(pTmpData, pData, MemSize);
Cmd.m_pData = pTmpData;
}
AddCmd(Cmd);
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 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;

View file

@ -321,9 +321,6 @@ private:
CAtlas m_TextureAtlas;
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
FT_Face m_DefaultFace = nullptr;
FT_Face m_IconFace = nullptr;
@ -485,13 +482,13 @@ private:
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)
{
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)
@ -510,6 +507,11 @@ private:
}
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 RealHeight = pBitmap->rows;
@ -544,23 +546,23 @@ private:
}
// 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)
{
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
UploadGlyph(FONT_TEXTURE_FILL, X, Y, Width, Height, m_aaGlyphData[FONT_TEXTURE_FILL]);
Grow(m_aaGlyphData[FONT_TEXTURE_FILL], m_aaGlyphData[FONT_TEXTURE_OUTLINE], Width, Height, OutlineThickness);
UploadGlyph(FONT_TEXTURE_OUTLINE, X, Y, Width, Height, m_aaGlyphData[FONT_TEXTURE_OUTLINE]);
UploadGlyph(FONT_TEXTURE_FILL, X, Y, Width, Height, pGlyphDataFill);
UploadGlyph(FONT_TEXTURE_OUTLINE, X, Y, Width, Height, pGlyphDataOutline);
}
// set glyph info
{
const int BmpWidth = pBitmap->width + x * 2;
const int BmpHeight = pBitmap->rows + y * 2;
Glyph.m_Height = Height;
Glyph.m_Width = Width;
Glyph.m_CharHeight = RealHeight;
@ -571,8 +573,8 @@ private:
Glyph.m_aUVs[0] = X;
Glyph.m_aUVs[1] = Y;
Glyph.m_aUVs[2] = Glyph.m_aUVs[0] + BmpWidth;
Glyph.m_aUVs[3] = Glyph.m_aUVs[1] + BmpHeight;
Glyph.m_aUVs[2] = Glyph.m_aUVs[0] + Width;
Glyph.m_aUVs[3] = Glyph.m_aUVs[1] + Height;
Glyph.m_State = SGlyph::EState::RENDERED;
}
@ -694,7 +696,7 @@ public:
for(size_t TextureIndex = 0; TextureIndex < NUM_FONT_TEXTURES; ++TextureIndex)
{
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);
@ -791,13 +793,12 @@ public:
}
const FT_Bitmap *pBitmap = &Face->glyph->bitmap;
// prepare glyph data
const size_t GlyphDataSize = (size_t)pBitmap->width * pBitmap->rows * sizeof(uint8_t);
if(pBitmap->pixel_mode == FT_PIXEL_MODE_GRAY)
mem_copy(m_aaGlyphData[FONT_TEXTURE_FILL], pBitmap->buffer, GlyphDataSize);
else
mem_zero(m_aaGlyphData[FONT_TEXTURE_FILL], GlyphDataSize);
if(pBitmap->pixel_mode != FT_PIXEL_MODE_GRAY)
{
log_debug("textrender", "Error loading glyph, unsupported pixel mode. Chr=%d GlyphIndex=%u PixelMode=%d", NextCharacter, GlyphIndex, pBitmap->pixel_mode);
pCurrent = pTmp;
continue;
}
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 ImgOffY = clamp(y + OffY, y, (y + TexSubHeight) - 1);
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; ++i)
for(size_t i = 0; i < PixelSize - 1; ++i)
{
if(i != PixelSize - 1)
{
*(TextImage.m_pData + ImageOffset + i) = 255;
}
else
{
*(TextImage.m_pData + ImageOffset + i) = *(m_aaGlyphData[FONT_TEXTURE_FILL] + GlyphOffset);
}
TextImage.m_pData[ImageOffset + i] = 255;
}
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
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 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;