Use One-Time Initialization for glyph run caching to avoid duplicate glyph run genera...
[gdipp.git] / gdipp_server / glyph_cache.cpp
blobd39930838106a9fb322a364dd733151f26b97851
1 #include "stdafx.h"
2 #include "glyph_cache.h"
3 #include "gdipp_lib/scoped_rw_lock.h"
4 #include "gdipp_server/global.h"
6 namespace gdipp
9 glyph_cache::string_id_type glyph_cache::get_string_id(const wchar_t *string, unsigned int count, bool is_glyph_index)
11 string_id_type string_id;
12 #ifdef _M_X64
13 MurmurHash3_x64_128(string, count * sizeof(wchar_t), is_glyph_index, &string_id);
14 #else
15 MurmurHash3_x86_128(string, count * sizeof(wchar_t), is_glyph_index, &string_id);
16 #endif // _M_X64
18 return string_id;
21 glyph_cache::char_id_type glyph_cache::get_char_id(uint128_t render_trait, FT_UInt index, bool is_glyph_index)
24 character ID:
25 * low 64 bits: low 64 bits of render_trait
26 * high 64 bits:
27 high low
28 | 31 | 1 | 32 |
29 | render_trait (65 - 96 bit) | is_glyph_index | index |
31 char_id_type char_id = render_trait;
32 char_id.second = (char_id.second << 33) | (static_cast<uint64_t>(is_glyph_index) << 32) | index;
33 return char_id;
36 glyph_cache::~glyph_cache()
38 for (std::map<char_id_type, INIT_ONCE>::iterator glyph_iter = _glyph_store.begin(); glyph_iter != _glyph_store.end(); ++glyph_iter)
40 BOOL pending;
41 FT_Glyph glyph;
42 InitOnceBeginInitialize(&glyph_iter->second, INIT_ONCE_CHECK_ONLY, &pending, reinterpret_cast<void **>(&glyph));
43 assert(!pending);
44 FT_Done_Glyph(glyph);
47 for (std::map<string_id_type, trait_to_run_map>::iterator str_iter = _glyph_run_store.begin(); str_iter != _glyph_run_store.end(); ++str_iter)
48 erase_glyph_run_cache_string(str_iter);
51 void glyph_cache::initialize()
53 _glyph_run_lru.resize(min(1 << server_cache_size, 16777216));
56 const FT_Glyph glyph_cache::lookup_glyph(char_id_type char_id)
58 std::map<char_id_type, INIT_ONCE>::iterator glyph_iter;
61 const scoped_rw_lock lock_w(scoped_rw_lock::SERVER_GLYPH_CACHE, false);
63 glyph_iter = _glyph_store.find(char_id);
64 if (glyph_iter == _glyph_store.end())
66 const std::pair<std::map<char_id_type, INIT_ONCE>::iterator, bool> insert_ret = _glyph_store.insert(std::pair<char_id_type, INIT_ONCE>(char_id, INIT_ONCE()));
67 assert(insert_ret.second);
68 glyph_iter = insert_ret.first;
69 InitOnceInitialize(&glyph_iter->second);
73 FT_Glyph glyph = NULL;
74 BOOL pending;
75 InitOnceBeginInitialize(&glyph_iter->second, 0, &pending, reinterpret_cast<void **>(&glyph));
76 assert((glyph == NULL) == pending);
78 return glyph;
81 bool glyph_cache::store_glyph(char_id_type char_id, const FT_Glyph glyph)
83 std::map<char_id_type, INIT_ONCE>::iterator glyph_iter;
86 const scoped_rw_lock lock_w(scoped_rw_lock::SERVER_GLYPH_CACHE, false);
88 glyph_iter = _glyph_store.find(char_id);
91 InitOnceComplete(&glyph_iter->second, (glyph == NULL ? INIT_ONCE_INIT_FAILED : 0), glyph);
92 return glyph != NULL;
95 const glyph_run *glyph_cache::lookup_glyph_run(string_id_type string_id, uint128_t render_trait)
97 trait_to_run_map::iterator trait_iter;
100 const scoped_rw_lock lock_w(scoped_rw_lock::SERVER_GLYPH_RUN_CACHE, false);
102 std::map<uint128_t, trait_to_run_map>::iterator str_iter = _glyph_run_store.find(string_id);
103 if (str_iter == _glyph_run_store.end())
105 const std::pair<std::map<string_id_type, trait_to_run_map>::iterator, bool> str_insert_ret = _glyph_run_store.insert(std::pair<string_id_type, trait_to_run_map>(string_id, trait_to_run_map()));
106 assert(str_insert_ret.second);
107 str_iter = str_insert_ret.first;
108 trait_iter = str_iter->second.end();
110 else
112 trait_iter = str_iter->second.find(render_trait);
115 if (trait_iter == str_iter->second.end())
117 const std::pair<trait_to_run_map::iterator, bool> trait_insert_ret = str_iter->second.insert(std::pair<uint128_t, INIT_ONCE>(render_trait, INIT_ONCE()));
118 assert(trait_insert_ret.second);
119 trait_iter = trait_insert_ret.first;
120 InitOnceInitialize(&trait_iter->second);
124 glyph_run *a_glyph_run = NULL;
125 BOOL pending;
126 InitOnceBeginInitialize(&trait_iter->second, 0, &pending, reinterpret_cast<void **>(&a_glyph_run));
127 assert((a_glyph_run == NULL) == pending);
129 return a_glyph_run;
132 bool glyph_cache::store_glyph_run(string_id_type string_id, uint128_t render_trait, glyph_run *a_glyph_run)
134 trait_to_run_map::iterator trait_iter;
137 bool b_ret;
138 string_id_type erased_str;
139 std::map<string_id_type, trait_to_run_map>::iterator str_iter;
141 const scoped_rw_lock lock_w(scoped_rw_lock::SERVER_GLYPH_RUN_CACHE, false);
143 b_ret = _glyph_run_lru.access(string_id, &erased_str);
144 if (b_ret)
146 // the string is evicted from LRU cache
147 // erase all cached glyph run that is under the evicted string ID
149 str_iter = _glyph_run_store.find(erased_str);
150 assert(str_iter != _glyph_run_store.end());
151 erase_glyph_run_cache_string(str_iter);
152 _glyph_run_store.erase(str_iter);
155 str_iter = _glyph_run_store.find(string_id);
156 assert(str_iter != _glyph_run_store.end());
157 trait_iter = str_iter->second.find(render_trait);
160 InitOnceComplete(&trait_iter->second, (a_glyph_run == NULL ? INIT_ONCE_INIT_FAILED : 0), a_glyph_run);
161 return a_glyph_run != NULL;
164 void glyph_cache::erase_glyph_run_cache_string(std::map<string_id_type, trait_to_run_map>::iterator str_iter)
166 for (trait_to_run_map::iterator trait_iter = str_iter->second.begin(); trait_iter != str_iter->second.end(); ++trait_iter)
168 BOOL pending;
169 glyph_run *a_glyph_run;
170 InitOnceBeginInitialize(&trait_iter->second, INIT_ONCE_CHECK_ONLY, &pending, reinterpret_cast<void **>(&a_glyph_run));
171 assert(!pending);
172 delete a_glyph_run;