-
Notifications
You must be signed in to change notification settings - Fork 21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature: GDI font cache #153
base: master
Are you sure you want to change the base?
Feature: GDI font cache #153
Conversation
161ee56
to
2e9b3e4
Compare
Thanks for separating the PR =) |
well on one hand yes: the (limited) gdi handles used is much lower, as the code creates shared_hfont-s for the "same" logfonts on top of that, the JsGdiFont getters are also setters (with some extras), making api usage much easier. however as to freeing JsGdiFont-s and releasing all shared_hfont-s: i've yet to get the gc kick in (using the default settings), and didn't really wanted to muck around in js:gc stuff until esr91 (reloading the test script panel seemed to release the "stuck(?)" JsGdiFont instances) |
(also, on a side note: i've tried to add the debug .cache getter as a static property of GdiFont, but failed, that's why it's available on every instance, heh) |
note2: note3: using a gibberish font name like "!INVALID" seems to get the system default font (Segoe) from the gdi font mapper, but keeping the gibberish name. |
after reading up a bit on js api / gc stuff, it seems that calling the c++ destructor only happens on gc finalization, and does not on "delete"ing / overwriting the GdiFont variable (as there's no js/es6 equivalent of a destructor callback), unless maybe some sort of non-obvious weakref trickery or is involved, so the best case for now is the lowered gdi handle count (normalized/shared+reused across panel instances in a foobar instance) |
A few issues:
|
It should be mentioned though, that I really appreciate your contributions - it's never easy working with someone else's codebase. PS: Concept stuff is neat, I should really spend some time familiarizing myself with it =) |
noted, will amend :)
if you mean dwrite, that's not included (yet), as the "drawtext/drawstring compatible" dwrite methods are in terrible need of refactoring/rethinking.
the default font size is always "-16" (depending on the font face, this means 12-14px actual size) according to my experiments (seems like the wine/reactos sources / tests confirm this, but i can't find the exact check myself in native ms dll-s using disassembly)
currently it's just a refcounted weakptr -> shared ptr cache, without any extra mechanisms, implementing an lru seemed like overkill, as reuse already helps reducing the gdi handle counts a lot.
the custom hash implementation is a bit of a micro-optimization story, as when "packing" the properties cached (and using one call to hash_combine vs one call for each property), afaik the "simpler" boost one may already lead to collisions than the alternative (which is a simple attempt to spread the bits more evenly than the former, the algo is explained on the link in the comment (which... became dead since apparently)... so here's a sw answer based on it : https://stackoverflow.com/a/50978188/1326931 ) |
I mean addition of Set* methods
LRU cache is not that complex (I think it would be around 100 LOC for a basic generic implementation), but it will greatly improve the scenario where user creates the same Font object in every
I do understand that std hash algorithm might not be the most optimal implementation, I just don't think that algorithm improvement brings anything noticeable to the table: even if we have 100 fonts and they will all have the collision (which is actually impossible), there will be most likely no performance impact at all, due to data locality. Such things usually only noticeable on HUGE number of keys (e.g. 10k). |
Real-life scenario: in our company we have a lot of 1mil+ sized unordered maps that use std hash. A lot of them are in pretty hot loops. We have yet to encounter a single case where there was a noticeable performance loss caused by inefficiency of std::hash. |
ah, those all call the "jsgdifont::reload" function, which tries to reuse an existing item from the cache if a matching one is already cached (the jsgdifont maintains a logfontw which is edited, and reloaded+normalized resulting in a possibly different shared_hfont ptr from the cache pool, when using the setters). |
i'm not overriding std:hash in any way, i'm just defining a function to combine two such hashes, which is useful when hashing struct-s. |
ec4585a
to
e180962
Compare
note: force-pushing because i've accidentally included stuff from #152 |
e180962
to
4e54457
Compare
My point still stands: font should be a read-only object - this is also the way font objects are treated in WinAPI and mainstream languages with built-in font objects as well (e.g. C#, Java). DWrite objects is a whole separate beast and I will probably make separate objects and methods for it anyway. There are also two other points that were not addressed: LRU cache implementation and GdiPlus object caching. |
that scenario is already handled: a shared_hfont wrapping the same HFONT should be returned from the cache as it is. (utilizing the internal reference counters of weak/shared_ptr-s) implementing an LRU is not that hard, but i'm not so sure about deleting references to fonts which are supposedly still used somewhere :/
hmm, looking at so, yes, there's improvements to be made in this regard. 👼 |
e9b749d
to
5c525e8
Compare
(rebased on merged master) |
c88e3f1
to
bd5de31
Compare
regarding GC: i think i'm found something in the comments ...could it be as simple as i'm a bit stuck on this one... maybe you have some insight? void JsGdiFont::Trace( JSTracer* trc, JSObject* obj )
{
if ( trc->isMarkingTracer() && ( __SOME_ADDITIONAL_CHECK__ ))
{
auto pNative = static_cast<JsGdiFont*>( JS_GetPrivate( obj ) );
pNative->font.reset();
}
} |
extracted the font cache feature as a separate PR from #147