Skip to content

Commit 94a82d7

Browse files
committed
Recycle temporary glyph buffers in FontFreeType.
1 parent e19730b commit 94a82d7

File tree

3 files changed

+105
-9
lines changed

3 files changed

+105
-9
lines changed

core/2d/FontAtlas.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,8 @@ bool FontAtlas::prepareLetterDefinitions(const std::u32string& utf32Text)
438438
}
439439
else
440440
{
441-
delete[] bitmap;
441+
if (bitmap)
442+
charRenderer->releaseBuffer(bitmap);
442443

443444
tempDef.validDefinition = !!tempDef.xAdvance;
444445
tempDef.width = 0;

core/2d/FontFreeType.cpp

Lines changed: 85 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,12 @@ FontFreeType::FontFreeType(bool distanceFieldEnabled /* = false */, float outlin
210210

211211
FontFreeType::~FontFreeType()
212212
{
213+
AX_ASSERT(_usedBuffers.empty());
214+
215+
for (const BufferPool& p : _availableBuffers)
216+
for (uint8_t* b : p.buffers)
217+
delete[] b;
218+
213219
if (_FTInitialized)
214220
{
215221
if (_stroker)
@@ -503,15 +509,15 @@ unsigned char* FontFreeType::getGlyphBitmapByIndex(unsigned int glyphIndex,
503509

504510
if (_outlineSize > 0 && outWidth > 0 && outHeight > 0)
505511
{
506-
auto copyBitmap = new unsigned char[outWidth * outHeight];
507-
memcpy(copyBitmap, ret, outWidth * outHeight * sizeof(unsigned char));
512+
uint8_t* const copyBitmap = acquireBuffer(outWidth * outHeight);
513+
memcpy(copyBitmap, ret, outWidth * outHeight * sizeof(uint8_t));
508514

509515
FT_BBox bbox;
510516
auto outlineBitmap = getGlyphBitmapWithOutline(glyphIndex, bbox);
511517
if (outlineBitmap == nullptr)
512518
{
513519
ret = nullptr;
514-
delete[] copyBitmap;
520+
releaseBuffer(copyBitmap);
515521
break;
516522
}
517523

@@ -540,7 +546,7 @@ unsigned char* FontFreeType::getGlyphBitmapByIndex(unsigned int glyphIndex,
540546
{
541547
FT_Pos index, index2;
542548
auto imageSize = blendWidth * blendHeight * 2;
543-
blendImage = new unsigned char[imageSize];
549+
blendImage = acquireBuffer(imageSize);
544550
memset(blendImage, 0, imageSize);
545551

546552
auto px = outlineMinX - blendImageMinX;
@@ -573,8 +579,8 @@ unsigned char* FontFreeType::getGlyphBitmapByIndex(unsigned int glyphIndex,
573579
outWidth = static_cast<int>(blendWidth);
574580
outHeight = static_cast<int>(blendHeight);
575581

576-
delete[] outlineBitmap;
577-
delete[] copyBitmap;
582+
releaseBuffer(outlineBitmap);
583+
releaseBuffer(copyBitmap);
578584
ret = blendImage;
579585
}
580586

@@ -588,6 +594,24 @@ unsigned char* FontFreeType::getGlyphBitmapByIndex(unsigned int glyphIndex,
588594
return nullptr;
589595
}
590596

597+
/**
598+
* Put the given buffer back into the pool of buffers.
599+
*/
600+
void FontFreeType::releaseBuffer(uint8_t* buffer)
601+
{
602+
const UsedBuffersMap::iterator it = _usedBuffers.find(buffer);
603+
AX_ASSERT(it != _usedBuffers.end());
604+
605+
for (BufferPool& p : _availableBuffers)
606+
if (p.capacity == it->second)
607+
{
608+
p.buffers.emplace_back(buffer);
609+
break;
610+
}
611+
612+
_usedBuffers.erase(it);
613+
}
614+
591615
unsigned char* FontFreeType::getGlyphBitmapWithOutline(unsigned int glyphIndex, FT_BBox& bbox)
592616
{
593617
unsigned char* ret = nullptr;
@@ -607,7 +631,7 @@ unsigned char* FontFreeType::getGlyphBitmapWithOutline(unsigned int glyphIndex,
607631
int32_t rows = static_cast<int32_t>((bbox.yMax - bbox.yMin) >> 6);
608632

609633
FT_Bitmap bmp;
610-
bmp.buffer = new unsigned char[width * rows];
634+
bmp.buffer = acquireBuffer(width * rows);
611635
memset(bmp.buffer, 0, width * rows);
612636
bmp.width = (int)width;
613637
bmp.rows = (int)rows;
@@ -653,7 +677,7 @@ void FontFreeType::renderCharAt(unsigned char* dest,
653677
memcpy(dest + (iX + (iY * atlasWidth)) * 2, bitmap + bitmap_y * 2, bitmapWidth * 2);
654678
++iY;
655679
}
656-
delete[] bitmap;
680+
releaseBuffer(bitmap);
657681
}
658682
else
659683
{
@@ -710,4 +734,57 @@ void FontFreeType::releaseFont(std::string_view fontName)
710734
}
711735
}
712736

737+
/**
738+
* Find a buffer with a capacity larger or equal to the given size. If there is
739+
* no such buffer, a new one is created. In all cases the returned buffer is
740+
* added to the used buffers list and will have to be released via
741+
* releaseBuffer.
742+
*/
743+
uint8_t* FontFreeType::acquireBuffer(size_t size)
744+
{
745+
const size_t n = _availableBuffers.size();
746+
747+
// Index of the first pool of large enough buffers. If we could not find a
748+
// buffer for the exact given size, this is also the index where a new pool
749+
// will be inserted, since it is the first larger than the size (or the end
750+
// of the list).
751+
size_t new_pool_index = n;
752+
753+
// Find the place where the best pool for our size should be (i.e. the first
754+
// pool for buffers of capacity greater or equal to the requested size).
755+
for (size_t i = 0; i != n; ++i)
756+
if (_availableBuffers[i].capacity >= size)
757+
{
758+
new_pool_index = i;
759+
break;
760+
}
761+
762+
// Now search for a pool with an available buffer.
763+
for (size_t i = new_pool_index; i != n; ++i)
764+
{
765+
BufferPool& p = _availableBuffers[i];
766+
767+
if (!p.buffers.empty())
768+
{
769+
uint8_t* const buffer = p.buffers.back();
770+
p.buffers.pop_back();
771+
_usedBuffers[buffer] = p.capacity;
772+
773+
return buffer;
774+
}
775+
}
776+
777+
if ((new_pool_index == n) || (_availableBuffers[new_pool_index].capacity != size))
778+
// Either all pools have capacities smaller than the requested size, or else
779+
// We have pools with capacity larger than the requested size but none had
780+
// an available buffer. We create a new pool for the requested size so
781+
// we'll be ready to receive the buffer in releaseBuffer.
782+
_availableBuffers.emplace(_availableBuffers.begin() + new_pool_index)->capacity = size;
783+
784+
uint8_t* const buffer(new uint8_t[size]);
785+
_usedBuffers[buffer] = size;
786+
787+
return buffer;
788+
}
789+
713790
}

core/2d/FontFreeType.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828

2929
#include "2d/Font.h"
3030
#include "2d/IFontEngine.h"
31+
3132
#include <string>
33+
#include <unordered_map>
3234

3335
namespace ax
3436
{
@@ -133,6 +135,7 @@ class AX_DLL FontFreeType : public Font
133135
int& outHeight,
134136
Rect& outRect,
135137
int& xAdvance);
138+
void releaseBuffer(uint8_t* buffer);
136139

137140
int getFontAscender() const;
138141
const char* getFontFamily() const;
@@ -169,6 +172,8 @@ class AX_DLL FontFreeType : public Font
169172

170173
void setGlyphCollection(GlyphCollection glyphs, std::string_view customGlyphs);
171174

175+
uint8_t* acquireBuffer(size_t size);
176+
172177
FT_Face _fontFace;
173178
FT_Stream _fontStream;
174179
FT_Stroker _stroker;
@@ -183,6 +188,19 @@ class AX_DLL FontFreeType : public Font
183188

184189
GlyphCollection _usedGlyphs;
185190
std::string _customGlyphs;
191+
192+
struct BufferPool
193+
{
194+
size_t capacity;
195+
std::vector<uint8_t*> buffers;
196+
};
197+
198+
using BufferPoolVector = std::vector<BufferPool>;
199+
using UsedBuffersMap = std::unordered_map<uint8_t*, size_t>;
200+
201+
/// Those are sorted by increasing capacity.
202+
BufferPoolVector _availableBuffers;
203+
UsedBuffersMap _usedBuffers;
186204
};
187205

188206
// end of _2d group

0 commit comments

Comments
 (0)