Permalink
Browse files

Get rid of collision-prone font cache keys. Stress the font cache a l…

…ittle less on slider dialogs.
  • Loading branch information...
hrydgard committed Nov 22, 2017
1 parent 543bb34 commit 3ecd7b4c0248f1fe428808ab135b2adf032bd7aa
@@ -74,6 +74,18 @@ class TextDrawer {
virtual void ClearCache() = 0;
void WrapString(std::string &out, const char *str, float maxWidth);
struct CacheKey {
bool operator < (const CacheKey &other) const {
if (fontHash < other.fontHash)
return true;
if (fontHash > other.fontHash)
return false;
return text < other.text;
}
std::string text;
uint32_t fontHash;
};
int frameCount_;
float fontScaleX_;
float fontScaleY_;
@@ -80,11 +80,9 @@ std::string TextDrawerAndroid::NormalizeString(std::string str) {
}
void TextDrawerAndroid::MeasureString(const char *str, size_t len, float *w, float *h) {
uint32_t stringHash = hash::Adler32((const uint8_t *)str, len);
uint32_t entryHash = stringHash ^ fontHash_;
CacheKey key{ std::string(str, len), fontHash_ };
TextMeasureEntry *entry;
auto iter = sizeCache_.find(entryHash);
auto iter = sizeCache_.find(key);
if (iter != sizeCache_.end()) {
entry = iter->second.get();
} else {
@@ -103,7 +101,7 @@ void TextDrawerAndroid::MeasureString(const char *str, size_t len, float *w, flo
entry = new TextMeasureEntry();
entry->width = (size >> 16);
entry->height = (size & 0xFFFF);
sizeCache_[entryHash] = std::unique_ptr<TextMeasureEntry>(entry);
sizeCache_[key] = std::unique_ptr<TextMeasureEntry>(entry);
}
entry->lastUsedFrame = frameCount_;
*w = entry->width * fontScaleX_ * dpiScale_;
@@ -130,11 +128,10 @@ void TextDrawerAndroid::MeasureStringRect(const char *str, size_t len, const Bou
float total_w = 0.0f;
float total_h = 0.0f;
for (size_t i = 0; i < lines.size(); i++) {
uint32_t stringHash = hash::Adler32((const uint8_t *)&lines[i][0], lines[i].length());
uint32_t entryHash = stringHash ^ fontHash_;
CacheKey key{ lines[i], fontHash_ };
TextMeasureEntry *entry;
auto iter = sizeCache_.find(entryHash);
auto iter = sizeCache_.find(key);
if (iter != sizeCache_.end()) {
entry = iter->second.get();
} else {
@@ -147,7 +144,7 @@ void TextDrawerAndroid::MeasureStringRect(const char *str, size_t len, const Bou
entry = new TextMeasureEntry();
entry->width = sizecx;
entry->height = sizecy;
sizeCache_[entryHash] = std::unique_ptr<TextMeasureEntry>(entry);
sizeCache_[key] = std::unique_ptr<TextMeasureEntry>(entry);
}
entry->lastUsedFrame = frameCount_;
@@ -166,14 +163,12 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x,
if (text.empty())
return;
uint32_t stringHash = hash::Adler32((const uint8_t *)text.data(), text.size());
uint32_t entryHash = stringHash ^ fontHash_ ^ (align << 24);
CacheKey key{ std::string(str), fontHash_ };
target.Flush(true);
TextStringEntry *entry;
auto iter = cache_.find(entryHash);
auto iter = cache_.find(key);
if (iter != cache_.end()) {
entry = iter->second.get();
entry->lastUsedFrame = frameCount_;
@@ -223,7 +218,7 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x,
desc.initData.push_back((uint8_t *)bitmapData);
entry->texture = draw_->CreateTexture(desc);
delete[] bitmapData;
cache_[entryHash] = std::unique_ptr<TextStringEntry>(entry);
cache_[key] = std::unique_ptr<TextStringEntry>(entry);
draw_->BindTexture(0, entry->texture);
}
float w = entry->bmWidth * fontScaleX_ * dpiScale_;
@@ -44,9 +44,8 @@ class TextDrawerAndroid : public TextDrawer {
std::map<uint32_t, AndroidFontEntry> fontMap_;
// The key is the CityHash of the string xor the fontHash_.
std::map<uint32_t, std::unique_ptr<TextStringEntry>> cache_;
std::map<uint32_t, std::unique_ptr<TextMeasureEntry>> sizeCache_;
std::map<CacheKey, std::unique_ptr<TextStringEntry>> cache_;
std::map<CacheKey, std::unique_ptr<TextMeasureEntry>> sizeCache_;
};
#endif
@@ -119,11 +119,10 @@ void TextDrawerWin32::SetFont(uint32_t fontHandle) {
}
void TextDrawerWin32::MeasureString(const char *str, size_t len, float *w, float *h) {
uint32_t stringHash = hash::Adler32((const uint8_t *)str, len);
uint32_t entryHash = stringHash ^ fontHash_;
CacheKey key{ std::string(str, len), fontHash_ };
TextMeasureEntry *entry;
auto iter = sizeCache_.find(entryHash);
auto iter = sizeCache_.find(key);
if (iter != sizeCache_.end()) {
entry = iter->second.get();
} else {
@@ -139,7 +138,7 @@ void TextDrawerWin32::MeasureString(const char *str, size_t len, float *w, float
entry = new TextMeasureEntry();
entry->width = size.cx;
entry->height = size.cy;
sizeCache_[entryHash] = std::unique_ptr<TextMeasureEntry>(entry);
sizeCache_[key] = std::unique_ptr<TextMeasureEntry>(entry);
}
entry->lastUsedFrame = frameCount_;
@@ -164,11 +163,10 @@ void TextDrawerWin32::MeasureStringRect(const char *str, size_t len, const Bound
float total_w = 0.0f;
float total_h = 0.0f;
for (size_t i = 0; i < lines.size(); i++) {
uint32_t stringHash = hash::Adler32((const uint8_t *)&lines[i][0], lines[i].length());
uint32_t entryHash = stringHash ^ fontHash_;
CacheKey key{ lines[i], fontHash_ };
TextMeasureEntry *entry;
auto iter = sizeCache_.find(entryHash);
auto iter = sizeCache_.find(key);
if (iter != sizeCache_.end()) {
entry = iter->second.get();
} else {
@@ -179,7 +177,7 @@ void TextDrawerWin32::MeasureStringRect(const char *str, size_t len, const Bound
entry = new TextMeasureEntry();
entry->width = size.cx;
entry->height = size.cy;
sizeCache_[entryHash] = std::unique_ptr<TextMeasureEntry>(entry);
sizeCache_[key] = std::unique_ptr<TextMeasureEntry>(entry);
}
entry->lastUsedFrame = frameCount_;
@@ -197,14 +195,13 @@ void TextDrawerWin32::DrawString(DrawBuffer &target, const char *str, float x, f
if (!strlen(str))
return;
uint32_t stringHash = hash::Adler32((const uint8_t *)str, strlen(str));
uint32_t entryHash = stringHash ^ fontHash_ ^ (align << 24);
CacheKey key{ std::string(str), fontHash_ };
target.Flush(true);
TextStringEntry *entry;
auto iter = cache_.find(entryHash);
auto iter = cache_.find(key);
if (iter != cache_.end()) {
entry = iter->second.get();
entry->lastUsedFrame = frameCount_;
@@ -304,7 +301,7 @@ void TextDrawerWin32::DrawString(DrawBuffer &target, const char *str, float x, f
delete[] bitmapData16;
if (bitmapData32)
delete[] bitmapData32;
cache_[entryHash] = std::unique_ptr<TextStringEntry>(entry);
cache_[key] = std::unique_ptr<TextStringEntry>(entry);
}
draw_->BindTexture(0, entry->texture);
@@ -36,9 +36,8 @@ class TextDrawerWin32 : public TextDrawer {
std::map<uint32_t, std::unique_ptr<TextDrawerFontContext>> fontMap_;
uint32_t fontHash_;
// The key is the CityHash of the string xor the fontHash_.
std::map<uint32_t, std::unique_ptr<TextStringEntry>> cache_;
std::map<uint32_t, std::unique_ptr<TextMeasureEntry>> sizeCache_;
std::map<CacheKey, std::unique_ptr<TextStringEntry>> cache_;
std::map<CacheKey, std::unique_ptr<TextMeasureEntry>> sizeCache_;
};
#endif
@@ -638,6 +638,7 @@ void SliderPopupScreen::CreatePopupContents(UI::ViewGroup *parent) {
edit_ = new TextEdit(temp, "", new LinearLayoutParams(10.0f));
edit_->SetMaxLen(16);
edit_->SetTextColor(dc.theme->popupStyle.fgColor);
edit_->SetTextAlign(FLAG_DYNAMIC_ASCII);
edit_->OnTextChange.Handle(this, &SliderPopupScreen::OnTextChange);
changing_ = false;
lin->Add(edit_);
@@ -668,6 +669,7 @@ void SliderFloatPopupScreen::CreatePopupContents(UI::ViewGroup *parent) {
edit_ = new TextEdit(temp, "", new LinearLayoutParams(10.0f));
edit_->SetMaxLen(16);
edit_->SetTextColor(dc.theme->popupStyle.fgColor);
edit_->SetTextAlign(FLAG_DYNAMIC_ASCII);
edit_->OnTextChange.Handle(this, &SliderFloatPopupScreen::OnTextChange);
changing_ = false;
lin->Add(edit_);
@@ -791,12 +791,12 @@ void TextEdit::Draw(UIContext &dc) {
dc.DrawTextRect(placeholderText_.c_str(), bounds_, c, ALIGN_CENTER);
}
} else {
dc.DrawTextRect(text_.c_str(), textBounds, textColor, ALIGN_VCENTER | ALIGN_LEFT);
dc.DrawTextRect(text_.c_str(), textBounds, textColor, ALIGN_VCENTER | ALIGN_LEFT | align_);
}
if (HasFocus()) {
// Hack to find the caret position. Might want to find a better way...
dc.MeasureTextCount(dc.theme->uiFont, 1.0f, 1.0f, text_.c_str(), caret_, &w, &h, ALIGN_VCENTER | ALIGN_LEFT);
dc.MeasureTextCount(dc.theme->uiFont, 1.0f, 1.0f, text_.c_str(), caret_, &w, &h, ALIGN_VCENTER | ALIGN_LEFT | align_);
float caretX = w - scrollPos_;
if (caretX > bounds_.w) {
scrollPos_ += caretX - bounds_.w;
@@ -811,7 +811,7 @@ void TextEdit::Draw(UIContext &dc) {
}
void TextEdit::GetContentDimensions(const UIContext &dc, float &w, float &h) const {
dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, text_.size() ? text_.c_str() : "Wj", &w, &h);
dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, text_.size() ? text_.c_str() : "Wj", &w, &h, align_);
w += 2;
h += 2;
}
@@ -1115,7 +1115,7 @@ void Slider::Draw(UIContext &dc) {
else
sprintf(temp, "%i", *value_);
dc.SetFontStyle(dc.theme->uiFont);
dc.DrawText(temp, bounds_.x2() - 22, bounds_.centerY(), dc.theme->popupStyle.fgColor, ALIGN_CENTER);
dc.DrawText(temp, bounds_.x2() - 22, bounds_.centerY(), dc.theme->popupStyle.fgColor, ALIGN_CENTER | FLAG_DYNAMIC_ASCII);
}
void Slider::Update() {
@@ -784,6 +784,7 @@ class TextEdit : public View {
void SetTextColor(uint32_t color) { textColor_ = color; hasTextColor_ = true; }
const std::string &GetText() const { return text_; }
void SetMaxLen(size_t maxLen) { maxLen_ = maxLen; }
void SetTextAlign(int align) { align_ = align; } // Only really useful for setting FLAG_DYNAMIC_ASCII
void GetContentDimensions(const UIContext &dc, float &w, float &h) const override;
void Draw(UIContext &dc) override;
@@ -805,6 +806,7 @@ class TextEdit : public View {
int scrollPos_ = 0;
size_t maxLen_;
bool ctrlDown_ = false; // TODO: Make some global mechanism for this.
int align_ = 0;
// TODO: Selections
};

0 comments on commit 3ecd7b4

Please sign in to comment.