mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-15 04:28:20 +00:00
More efficient glyph uploading, fix crash with very large glyphs
Avoid using the `m_aaGlyphData` temporary buffer for uploading glyphs. Instead, allocate the required memory for the glyphs directly and allow the graphics backend to take ownership of the buffer when updating text textures. This avoids copying the glyph data into the temporary buffer when uploading individual glyphs. This also avoids crashes when rendering very large glyphs with large font sizes, due to the buffer `m_aaGlyphData` having a fixed size of `64 * 1024` while the maximum glyph size is not checked. This fixed size could be exceeded with glyphs larger than 256² in rendered dimensions. There should currently be no glyph in our fonts which is that large and also no font size so large that this could happen.
This commit is contained in:
parent
a7a5c0ea7a
commit
fe78331e80
|
@ -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;
|
||||||
|
|
||||||
const size_t MemSize = Width * Height;
|
if(IsMovedPointer)
|
||||||
uint8_t *pTmpData = static_cast<uint8_t *>(malloc(MemSize));
|
{
|
||||||
mem_copy(pTmpData, pData, MemSize);
|
Cmd.m_pData = pData;
|
||||||
Cmd.m_pData = pTmpData;
|
}
|
||||||
|
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);
|
AddCmd(Cmd);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
@ -549,16 +546,19 @@ 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
|
||||||
|
@ -696,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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue