From 0926cf2cb21c4159c71c997de02ac0dbd4a2bf76 Mon Sep 17 00:00:00 2001 From: Crend King Date: Tue, 10 Jan 2012 01:07:52 -0800 Subject: [PATCH] Use One-Time Initialization for glyph run caching to avoid duplicate glyph run generation. --- gdipp_lib/lru.h | 17 ++++---- gdipp_server/font_mgr.cpp | 19 ++++---- gdipp_server/font_mgr.h | 4 +- gdipp_server/glyph_cache.cpp | 101 +++++++++++++++++++++++++++++-------------- gdipp_server/glyph_cache.h | 6 ++- gdipp_server/os2_metrics.cpp | 2 +- gdipp_server/rpc_server.cpp | 2 +- 7 files changed, 92 insertions(+), 59 deletions(-) diff --git a/gdipp_lib/lru.h b/gdipp_lib/lru.h index 3d2b850..6015ff0 100644 --- a/gdipp_lib/lru.h +++ b/gdipp_lib/lru.h @@ -24,14 +24,14 @@ public: _capacity = new_capacity; } - bool access(const T data, T &erased) + bool access(const T data, T *erased) { - const scoped_rw_lock lock_w(scoped_rw_lock::LIB_LRU, false); - bool overflow = false; - _map_type::iterator iter = _data_map.find(data); - if (iter == _data_map.end()) + const scoped_rw_lock lock_w(scoped_rw_lock::LIB_LRU, false); + + _map_type::iterator data_iter = _data_map.find(data); + if (data_iter == _data_map.end()) { // data never accessed @@ -39,9 +39,9 @@ public: { // list is full // erase and return the last accessed data - erased = _access_list.back(); + erased = &_access_list.back(); _access_list.pop_back(); - _data_map.erase(erased); + _data_map.erase(*erased); overflow = true; } @@ -53,8 +53,7 @@ public: { // data accessed before // move it to the most recent position - // - _list_iter_type node = iter->second; + _list_iter_type node = data_iter->second; if (node != _access_list.begin()) _access_list.splice(_access_list.begin(), _access_list, node); diff --git a/gdipp_server/font_mgr.cpp b/gdipp_server/font_mgr.cpp index f71d06c..0495b80 100644 --- a/gdipp_server/font_mgr.cpp +++ b/gdipp_server/font_mgr.cpp @@ -86,7 +86,7 @@ font_mgr::font_mgr() font_mgr::~font_mgr() { - for (std::map::const_iterator iter = _font_registry.begin(); iter != _font_registry.end(); ++iter) + for (std::map::const_iterator iter = _font_registry.begin(); iter != _font_registry.end(); ++iter) DeleteObject(iter->second.font_handle); TlsFree(_font_holder_tls_index); @@ -98,9 +98,6 @@ void *font_mgr::register_font(HDC font_holder, const LOGFONTW *log_font, BYTE ** bool b_ret; - std::wstring font_face; - std::map::iterator font_iter; - const HFONT hfont = CreateFontIndirectW(log_font); if (hfont == NULL) return NULL; @@ -115,8 +112,8 @@ void *font_mgr::register_font(HDC font_holder, const LOGFONTW *log_font, BYTE ** } const OUTLINETEXTMETRICW *outline_metrics = reinterpret_cast(*outline_metrics_buf); - font_face = metric_face_name(outline_metrics); - font_iter = _font_registry.find(font_face); + const std::wstring font_face = metric_face_name(outline_metrics); + std::map::iterator font_iter = _font_registry.find(font_face); if (font_iter == _font_registry.end()) { const scoped_rw_lock lock_w(scoped_rw_lock::SERVER_FONT_MGR, false); @@ -150,7 +147,7 @@ void *font_mgr::register_font(HDC font_holder, const LOGFONTW *log_font, BYTE ** } } - const std::pair::iterator, bool> insert_ret = _font_registry.insert(std::pair(font_face, font_entry())); + const std::pair::iterator, bool> insert_ret = _font_registry.insert(std::pair(font_face, _font_entry())); assert(insert_ret.second); font_iter = insert_ret.first; @@ -176,25 +173,25 @@ void *font_mgr::register_font(HDC font_holder, const LOGFONTW *log_font, BYTE ** HFONT font_mgr::select_font(void *font_id, HDC hdc) const { - const font_entry *curr_font = reinterpret_cast(font_id); + const _font_entry *curr_font = reinterpret_cast(font_id); return reinterpret_cast(SelectObject(hdc, curr_font->font_handle)); } ULONG font_mgr::lookup_face_index(void *font_id) const { - const font_entry *curr_font = reinterpret_cast(font_id); + const _font_entry *curr_font = reinterpret_cast(font_id); return curr_font->face_index; } const os2_metrics *font_mgr::lookup_os2_metrics(void *font_id) const { - const font_entry *curr_font = reinterpret_cast(font_id); + const _font_entry *curr_font = reinterpret_cast(font_id); return &curr_font->os2; } FT_Stream font_mgr::lookup_stream(void *font_id) const { - font_entry *curr_font = reinterpret_cast(font_id); + _font_entry *curr_font = reinterpret_cast<_font_entry *>(font_id); return &curr_font->stream; } diff --git a/gdipp_server/font_mgr.h b/gdipp_server/font_mgr.h index f5e6103..a23a682 100644 --- a/gdipp_server/font_mgr.h +++ b/gdipp_server/font_mgr.h @@ -32,7 +32,7 @@ public: BOOL set_thread_font_holder(HDC font_holder) const; private: - struct font_entry + struct _font_entry { // all fields are font-specific and thread-safe invariants @@ -49,7 +49,7 @@ private: static unsigned long stream_io(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count); static void stream_close(FT_Stream stream); - std::map _font_registry; + std::map _font_registry; DWORD _font_holder_tls_index; }; diff --git a/gdipp_server/glyph_cache.cpp b/gdipp_server/glyph_cache.cpp index 42e5fa2..d399308 100644 --- a/gdipp_server/glyph_cache.cpp +++ b/gdipp_server/glyph_cache.cpp @@ -40,14 +40,12 @@ glyph_cache::~glyph_cache() BOOL pending; FT_Glyph glyph; InitOnceBeginInitialize(&glyph_iter->second, INIT_ONCE_CHECK_ONLY, &pending, reinterpret_cast(&glyph)); + assert(!pending); FT_Done_Glyph(glyph); } - for (std::map::const_iterator str_iter = _glyph_run_store.begin(); str_iter != _glyph_run_store.end(); ++str_iter) - { - for (trait_to_run_map::const_iterator trait_iter = str_iter->second.begin(); trait_iter != str_iter->second.end(); ++trait_iter) - delete trait_iter->second; - } + for (std::map::iterator str_iter = _glyph_run_store.begin(); str_iter != _glyph_run_store.end(); ++str_iter) + erase_glyph_run_cache_string(str_iter); } void glyph_cache::initialize() @@ -94,48 +92,85 @@ bool glyph_cache::store_glyph(char_id_type char_id, const FT_Glyph glyph) return glyph != NULL; } -const glyph_run *glyph_cache::lookup_glyph_run(string_id_type string_id, uint128_t render_trait) const +const glyph_run *glyph_cache::lookup_glyph_run(string_id_type string_id, uint128_t render_trait) { - const scoped_rw_lock lock_r(scoped_rw_lock::SERVER_GLYPH_RUN_CACHE, true); + trait_to_run_map::iterator trait_iter; - std::map::const_iterator str_iter = _glyph_run_store.find(string_id); - if (str_iter == _glyph_run_store.end()) - return NULL; + { + const scoped_rw_lock lock_w(scoped_rw_lock::SERVER_GLYPH_RUN_CACHE, false); - trait_to_run_map::const_iterator trait_iter = str_iter->second.find(render_trait); - if (trait_iter == str_iter->second.end()) - return NULL; + std::map::iterator str_iter = _glyph_run_store.find(string_id); + if (str_iter == _glyph_run_store.end()) + { + const std::pair::iterator, bool> str_insert_ret = _glyph_run_store.insert(std::pair(string_id, trait_to_run_map())); + assert(str_insert_ret.second); + str_iter = str_insert_ret.first; + trait_iter = str_iter->second.end(); + } + else + { + trait_iter = str_iter->second.find(render_trait); + } + + if (trait_iter == str_iter->second.end()) + { + const std::pair trait_insert_ret = str_iter->second.insert(std::pair(render_trait, INIT_ONCE())); + assert(trait_insert_ret.second); + trait_iter = trait_insert_ret.first; + InitOnceInitialize(&trait_iter->second); + } + } + + glyph_run *a_glyph_run = NULL; + BOOL pending; + InitOnceBeginInitialize(&trait_iter->second, 0, &pending, reinterpret_cast(&a_glyph_run)); + assert((a_glyph_run == NULL) == pending); - return trait_iter->second; + return a_glyph_run; } bool glyph_cache::store_glyph_run(string_id_type string_id, uint128_t render_trait, glyph_run *a_glyph_run) { - bool b_ret; - string_id_type erased_str; + trait_to_run_map::iterator trait_iter; - const scoped_rw_lock lock_w(scoped_rw_lock::SERVER_GLYPH_RUN_CACHE, false); - - b_ret = _glyph_run_lru.access(string_id, erased_str); - if (b_ret) { - // the string is evicted from LRU cache - // erase all cached glyph run that is under the evicted string ID - - std::map::iterator str_iter = _glyph_run_store.find(erased_str); - assert(str_iter != _glyph_run_store.end()); - - for (trait_to_run_map::const_iterator trait_iter = str_iter->second.begin(); trait_iter != str_iter->second.end(); ++trait_iter) - delete trait_iter->second; + bool b_ret; + string_id_type erased_str; + std::map::iterator str_iter; + + const scoped_rw_lock lock_w(scoped_rw_lock::SERVER_GLYPH_RUN_CACHE, false); + + b_ret = _glyph_run_lru.access(string_id, &erased_str); + if (b_ret) + { + // the string is evicted from LRU cache + // erase all cached glyph run that is under the evicted string ID + + str_iter = _glyph_run_store.find(erased_str); + assert(str_iter != _glyph_run_store.end()); + erase_glyph_run_cache_string(str_iter); + _glyph_run_store.erase(str_iter); + } - _glyph_run_store.erase(str_iter); + str_iter = _glyph_run_store.find(string_id); + assert(str_iter != _glyph_run_store.end()); + trait_iter = str_iter->second.find(render_trait); } - // after eviction, insert new glyph_run - const std::pair::iterator, bool> str_insert_ret = _glyph_run_store.insert(std::pair(string_id, trait_to_run_map())); - const std::pair trait_insert_ret = str_insert_ret.first->second.insert(std::pair(render_trait, a_glyph_run)); + InitOnceComplete(&trait_iter->second, (a_glyph_run == NULL ? INIT_ONCE_INIT_FAILED : 0), a_glyph_run); + return a_glyph_run != NULL; +} - return trait_insert_ret.second; +void glyph_cache::erase_glyph_run_cache_string(std::map::iterator str_iter) +{ + for (trait_to_run_map::iterator trait_iter = str_iter->second.begin(); trait_iter != str_iter->second.end(); ++trait_iter) + { + BOOL pending; + glyph_run *a_glyph_run; + InitOnceBeginInitialize(&trait_iter->second, INIT_ONCE_CHECK_ONLY, &pending, reinterpret_cast(&a_glyph_run)); + assert(!pending); + delete a_glyph_run; + } } } diff --git a/gdipp_server/glyph_cache.h b/gdipp_server/glyph_cache.h index 1a40223..a74346f 100644 --- a/gdipp_server/glyph_cache.h +++ b/gdipp_server/glyph_cache.h @@ -22,12 +22,14 @@ public: const FT_Glyph lookup_glyph(char_id_type char_id); bool store_glyph(char_id_type char_id, const FT_Glyph glyph); - const glyph_run *lookup_glyph_run(string_id_type string_id, uint128_t render_trait) const; + const glyph_run *lookup_glyph_run(string_id_type string_id, uint128_t render_trait); bool store_glyph_run(string_id_type string_id, uint128_t render_trait, glyph_run *a_glyph_run); private: // std::map from render trait to glyph run - typedef std::map trait_to_run_map; + typedef std::map trait_to_run_map; + + void erase_glyph_run_cache_string(std::map::iterator str_iter); // std::map from character ID (including character index and render trait) to its glyph std::map _glyph_store; diff --git a/gdipp_server/os2_metrics.cpp b/gdipp_server/os2_metrics.cpp index e094d64..0faeb04 100644 --- a/gdipp_server/os2_metrics.cpp +++ b/gdipp_server/os2_metrics.cpp @@ -49,7 +49,7 @@ bool os2_metrics::init(void *font_id) DWORD font_data_size; - HDC font_holder = dc_pool_instance.claim(); + const HDC font_holder = dc_pool_instance.claim(); assert(font_holder != NULL); font_mgr_instance.select_font(font_id, font_holder); diff --git a/gdipp_server/rpc_server.cpp b/gdipp_server/rpc_server.cpp index 284c267..63314b2 100644 --- a/gdipp_server/rpc_server.cpp +++ b/gdipp_server/rpc_server.cpp @@ -185,7 +185,7 @@ void __RPC_USER MIDL_user_free(void __RPC_FAR *ptr) if (logfont_size != sizeof(LOGFONTW)) return RPC_S_INVALID_ARG; - HDC session_font_holder = gdipp::dc_pool_instance.claim(); + const HDC session_font_holder = gdipp::dc_pool_instance.claim(); assert(session_font_holder != NULL); // register font with given LOGFONT structure -- 2.11.4.GIT