Fix crash with truetype fonts and multi threading (#9424)

This commit is contained in:
ζeh Matt 2019-06-16 17:43:53 +02:00 committed by Michael Steenbeek
parent 6b7fee86bb
commit 7c0f04903e
2 changed files with 98 additions and 52 deletions

View File

@ -59,6 +59,7 @@
- Fix: [#9324] Crash trying to remove invalid footpath scenery.
- Fix: [#9402] Ad campaigns disappear when you save and load the game.
- Fix: [#9411] Ad campaigns end too soon.
- Fix: [#9424] Crash using multi threading with TrueType fonts.
- Fix: Guests eating popcorn are drawn as if they're eating pizza.
- Fix: The arbitrary ride type and vehicle dropdown lists are ordered case-sensitively.
- Improved: [#6116] Expose colour scheme for track elements in the tile inspector.

View File

@ -9,6 +9,8 @@
#ifndef NO_TTF
# include <atomic>
# include <mutex>
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdocumentation"
# include <ft2build.h>
@ -53,6 +55,8 @@ static int32_t _ttfGetWidthCacheCount = 0;
static int32_t _ttfGetWidthCacheHitCount = 0;
static int32_t _ttfGetWidthCacheMissCount = 0;
static std::mutex _mutex;
static TTF_Font* ttf_open_font(const utf8* fontPath, int32_t ptSize);
static void ttf_close_font(TTF_Font* font);
static uint32_t ttf_surface_cache_hash(TTF_Font* font, const utf8* text);
@ -60,63 +64,111 @@ static void ttf_surface_cache_dispose(ttf_cache_entry* entry);
static void ttf_surface_cache_dispose_all();
static void ttf_getwidth_cache_dispose_all();
static bool ttf_get_size(TTF_Font* font, const utf8* text, int32_t* width, int32_t* height);
static void ttf_toggle_hinting(bool);
static TTFSurface* ttf_render(TTF_Font* font, const utf8* text);
template<typename T> class FontLockHelper
{
T& _mutex;
const bool _enabled;
public:
FontLockHelper(T& mutex)
: _mutex(mutex)
, _enabled(gConfigGeneral.multithreading)
{
if (_enabled)
_mutex.lock();
}
~FontLockHelper()
{
if (_enabled)
_mutex.unlock();
}
};
static void ttf_toggle_hinting(bool)
{
if (!LocalisationService_UseTrueTypeFont())
{
return;
}
for (int32_t i = 0; i < FONT_SIZE_COUNT; i++)
{
TTFFontDescriptor* fontDesc = &(gCurrentTTFFontSet->size[i]);
bool use_hinting = gConfigFonts.enable_hinting && fontDesc->hinting_threshold;
TTF_SetFontHinting(fontDesc->font, use_hinting ? 1 : 0);
}
if (_ttfSurfaceCacheCount)
{
ttf_surface_cache_dispose_all();
}
}
bool ttf_initialise()
{
if (!_ttfInitialised)
FontLockHelper<std::mutex> lock(_mutex);
if (_ttfInitialised)
return true;
if (TTF_Init() != 0)
{
if (TTF_Init() != 0)
log_error("Couldn't initialise FreeType engine");
return false;
}
for (int32_t i = 0; i < FONT_SIZE_COUNT; i++)
{
TTFFontDescriptor* fontDesc = &(gCurrentTTFFontSet->size[i]);
utf8 fontPath[MAX_PATH];
if (!platform_get_font_path(fontDesc, fontPath, sizeof(fontPath)))
{
log_error("Couldn't initialise FreeType engine");
log_verbose("Unable to load font '%s'", fontDesc->font_name);
return false;
}
for (int32_t i = 0; i < FONT_SIZE_COUNT; i++)
fontDesc->font = ttf_open_font(fontPath, fontDesc->ptSize);
if (fontDesc->font == nullptr)
{
TTFFontDescriptor* fontDesc = &(gCurrentTTFFontSet->size[i]);
utf8 fontPath[MAX_PATH];
if (!platform_get_font_path(fontDesc, fontPath, sizeof(fontPath)))
{
log_verbose("Unable to load font '%s'", fontDesc->font_name);
return false;
}
fontDesc->font = ttf_open_font(fontPath, fontDesc->ptSize);
if (fontDesc->font == nullptr)
{
log_verbose("Unable to load '%s'", fontPath);
return false;
}
log_verbose("Unable to load '%s'", fontPath);
return false;
}
ttf_toggle_hinting();
_ttfInitialised = true;
}
ttf_toggle_hinting(true);
_ttfInitialised = true;
return true;
}
void ttf_dispose()
{
if (_ttfInitialised)
FontLockHelper<std::mutex> lock(_mutex);
if (!_ttfInitialised)
return;
ttf_surface_cache_dispose_all();
ttf_getwidth_cache_dispose_all();
for (int32_t i = 0; i < FONT_SIZE_COUNT; i++)
{
ttf_surface_cache_dispose_all();
ttf_getwidth_cache_dispose_all();
for (int32_t i = 0; i < FONT_SIZE_COUNT; i++)
TTFFontDescriptor* fontDesc = &(gCurrentTTFFontSet->size[i]);
if (fontDesc->font != nullptr)
{
TTFFontDescriptor* fontDesc = &(gCurrentTTFFontSet->size[i]);
if (fontDesc->font != nullptr)
{
ttf_close_font(fontDesc->font);
fontDesc->font = nullptr;
}
ttf_close_font(fontDesc->font);
fontDesc->font = nullptr;
}
TTF_Quit();
_ttfInitialised = false;
}
TTF_Quit();
_ttfInitialised = false;
}
static TTF_Font* ttf_open_font(const utf8* fontPath, int32_t ptSize)
@ -163,22 +215,8 @@ static void ttf_surface_cache_dispose_all()
void ttf_toggle_hinting()
{
if (!LocalisationService_UseTrueTypeFont())
{
return;
}
for (int32_t i = 0; i < FONT_SIZE_COUNT; i++)
{
TTFFontDescriptor* fontDesc = &(gCurrentTTFFontSet->size[i]);
bool use_hinting = gConfigFonts.enable_hinting && fontDesc->hinting_threshold;
TTF_SetFontHinting(fontDesc->font, use_hinting ? 1 : 0);
}
if (_ttfSurfaceCacheCount)
{
ttf_surface_cache_dispose_all();
}
FontLockHelper<std::mutex> lock(_mutex);
ttf_toggle_hinting(true);
}
TTFSurface* ttf_surface_cache_get_or_add(TTF_Font* font, const utf8* text)
@ -187,6 +225,9 @@ TTFSurface* ttf_surface_cache_get_or_add(TTF_Font* font, const utf8* text)
uint32_t hash = ttf_surface_cache_hash(font, text);
int32_t index = hash % TTF_SURFACE_CACHE_SIZE;
FontLockHelper<std::mutex> lock(_mutex);
for (int32_t i = 0; i < TTF_SURFACE_CACHE_SIZE; i++)
{
entry = &_ttfSurfaceCache[index];
@ -260,6 +301,9 @@ uint32_t ttf_getwidth_cache_get_or_add(TTF_Font* font, const utf8* text)
uint32_t hash = ttf_surface_cache_hash(font, text);
int32_t index = hash % TTF_GETWIDTH_CACHE_SIZE;
FontLockHelper<std::mutex> lock(_mutex);
for (int32_t i = 0; i < TTF_GETWIDTH_CACHE_SIZE; i++)
{
entry = &_ttfGetWidthCache[index];
@ -304,6 +348,7 @@ uint32_t ttf_getwidth_cache_get_or_add(TTF_Font* font, const utf8* text)
TTFFontDescriptor* ttf_get_font_from_sprite_base(uint16_t spriteBase)
{
FontLockHelper<std::mutex> lock(_mutex);
return &gCurrentTTFFontSet->size[font_get_size_from_sprite_base(spriteBase)];
}