Skip to content
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

Use the same FT load flags in HB as in FT #230

Merged
merged 5 commits into from
Aug 18, 2018
Merged

Conversation

NiLuJe
Copy link
Member

@NiLuJe NiLuJe commented Aug 17, 2018

Avoids mismatches & broke-ass advances

Avoids mismatches & broke-ass advances
@NiLuJe
Copy link
Member Author

NiLuJe commented Aug 17, 2018

That seems like the sane thing to do, and is what raqm does, FWIW.

Hopefully leads to much more consistent results w/ HB + hinting. (I, err, did not test it :D).

if (!_hb_font)
error = FT_Err_Invalid_Argument;
// Use the same load flags as we do when using FT directly, to avoid mismatching advances & raster
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the added part should be in a else {...} (if _hb_font ok) (not sure what happens next when _hb_font fails :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed! I mistakenly thought the error path was a return, for, err, some reason? :D.

Thought that error was a return, for some reason >_<".
@poire-z
Copy link
Contributor

poire-z commented Aug 18, 2018

And, as the flags may change widths and lines layout, and previously cached calculations may not match how words will be drawn after that, you'd better increment this:

/// increment following value to force re-formatting of old book after load
#define FORMATTING_VERSION_ID 0x0009

(although just toggling any setting and back will re-render the document correctly when one feels it looks ugly)

error = FT_Err_Invalid_Argument;
} else {
// Use the same load flags as we do when using FT directly, to avoid mismatching advances & raster
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, excellent!

So by default it uses the hinting as specified by the font or something? 'cause I only see auto and no hint.

Copy link
Member Author

@NiLuJe NiLuJe Aug 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It defaults to FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING (i.e., no hinting)... for apparently complex legacy reasons (the one release that flipped the defaults lasted all of 24h, because that massively broke firefox :D).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought all relevant hinting patents had expired?

Could you link me to the Firefox thing? I must be out of the loop on that one. I guess the Mozilla dev thingy blog doesn't advertise their own failures. :-D

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://github.com/harfbuzz/harfbuzz/issues/143

Copy link
Member

@Frenzie Frenzie Aug 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I thought you meant within the past few weeks. I may have a vague recollection of that thing from a few years back. :-)

@poire-z poire-z merged commit c02f597 into koreader:master Aug 18, 2018
@poire-z
Copy link
Contributor

poire-z commented Aug 18, 2018

Mhhhh. Performance with harfbuzz went dramatically down with this.
Timing of the pure rendering phase (rendering document... rendering done) of my 6000 pages book on the emulator

  • freetype kerning: 5s (60s total load time on my kobo, so rendering time ~20s)
  • harfbuzz kerning before this PR: 12s (80s total load time on my kobo, so rendering time ~40s)
  • harfbuzz kerning after this PR: 65s (not measured on my kobo, but probably~280s total load time with 240s rendering time).

If you // comment the two added hb_ft_font_set_load_flags(_hb_font, flags);, you get back the previous performance (12s).

I don't have the eyes and taste to catch any mismatches & broke-ass advances if there are any, so I can't say if this is really needed or not.

@NiLuJe
Copy link
Member Author

NiLuJe commented Aug 18, 2018

I was expecting a hit, but admittedly not that severe... ;).

@poire-z
Copy link
Contributor

poire-z commented Aug 18, 2018

But if you use FT_LOAD_RENDER (which must just loads metrics) instead of FT_LOAD_DEFAULT (which must load glyphs), you get back the 12s ! :)

@poire-z
Copy link
Contributor

poire-z commented Aug 18, 2018

Oups, no, you don't :( (forgot to uncomment the hb_ft_font_set_load_flags...)

@poire-z
Copy link
Contributor

poire-z commented Aug 19, 2018

Well, it's superslow whatever the flags, except when you use the flags that are the defaults in harfbuzz: flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
https://github.com/harfbuzz/harfbuzz/blob/master/src/hb-ft.cc#L85

There's also somes notes marked TODO at https://github.com/harfbuzz/harfbuzz/blob/22defe0965adddaa09eebc13df7fa6c64e2abba3/src/hb-ft.cc#L42-L62

 *   - FreeType works in 26.6 mode.  Clients can decide to use that mode, and everything
 *     would work fine.  However, we also abuse this API for performing in font-space,
 *     but don't pass the correct flags to FreeType.  We just abuse the no-hinting mode
 *     for that, such that no rounding etc happens.  As such, we don't set ppem, and
 *     pass NO_HINTING as load_flags.  Would be much better to use NO_SCALE, and scale
 *     ourselves, like we do in uniscribe, etc.

So, revert the flags parts? Or do you have some other ideas?

Also, if we were to keep that, there's more to do: they are currently just set from the _hintingMode value at font load time - _hintingMode may be changed later when hinting is changed, and the flags would currently not be updated - it would need the same kind of thing done in

virtual void setHintingMode(hinting_mode_t mode) {
if (_hintingMode == mode)
return;
_hintingMode = mode;
clearCache();
}

which is called for each loaded font when the global hinting mode is changed by:
virtual void SetHintingMode(hinting_mode_t mode) {
if (_hintingMode == mode)
return;
FONT_MAN_GUARD
CRLog::debug("Hinting mode is changed: %d", (int)mode);
_hintingMode = mode;
gc();
clearGlyphCache();
LVPtrVector< LVFontCacheItem > * fonts = _cache.getInstances();
for ( int i=0; i<fonts->length(); i++ ) {
fonts->get(i)->getFont()->setHintingMode(mode);
}
}

@NiLuJe
Copy link
Member Author

NiLuJe commented Aug 19, 2018

I'll take a look at it later tonight (but, yeah, I smell a commenting out coming ;D).

(And yeah, HB is aware that this is slow with hinting enabled, there's a couple issues/PRs on the subject, besides the recommendations of caching as much stuff as possible on the app's side).

@poire-z
Copy link
Contributor

poire-z commented Aug 19, 2018

(btw, I haven't seen anything wrong with the current enhanced mode, and I'm even beginning to like it, and the more condensed words it gives)

@NiLuJe
Copy link
Member Author

NiLuJe commented Aug 19, 2018

Okay, so, clearly, it's not viable as-is in terms of performance.

But on the other hand, the other behavior seems somewhat broken, which explains the crazy spacing variations.

(f.g., with the matched flags, I get a result that's basically identical to FT, but with proper kerning, the spacing of non-kerned pairs is untouched, which makes sense, and was pretty much the point of the whole thing ;)).

@NiLuJe
Copy link
Member Author

NiLuJe commented Aug 19, 2018

Okay, a few comparison shots.

FeeType, AutoHint
ft_auto

FreeType linked against HarfBuzz, AutoHint
_fthb_auto

Fairly identical results, only the hyphen is a tad more compressed on the second shot.

@NiLuJe
Copy link
Member Author

NiLuJe commented Aug 19, 2018

FreeType, Native hinting
ft_native

FreeType linked against HarfBuzz, Native hinting
_fthb_native

Exact same observations, only the line w/ the hyphenation see a tiiiiny change.

@NiLuJe
Copy link
Member Author

NiLuJe commented Aug 19, 2018

HarfBuzz, AutoHint
hb_auto

Harfbuzz, Native hinting
hb_native

Spacing is weird/gone (but that actually looks fairly decent w/ Noto Serif, at this size, at least).

@NiLuJe
Copy link
Member Author

NiLuJe commented Aug 19, 2018

HarfBuzz, matching flags, Native
hb_flags_native

HarfBuzz, matching flags, AutoHint
hb_flags_auto

General spacing matches the FT result, but with kerning pairs apparently better obeyed.

@NiLuJe
Copy link
Member Author

NiLuJe commented Aug 19, 2018

Now, shit starts getting weird.

HarfBuzz, matching flags, autohinter, with a FT linked against HB.
_full_auto

That's my preferred result, right there! And, again, general spacing matches the FT linked w/ HB results.

And now, for the weird one:
HarfBuzz, matching flags, native hinting, with a FT linked against HB.

_full_native

This one's a mess, plain and simple.
Not quite sure why, possibly because we're not actually passing the right flags for the native hinter (which can be slightly difficult to actually explicitly request).

@NiLuJe
Copy link
Member Author

NiLuJe commented Aug 19, 2018

@poire-z : I don't quite get how we actually end up with the native hinter in CRE... Is that the default case, and hoping FT was built w/ native hinting enabled? Because that might need an explicit FT_LOAD_NO_AUTOHINT flag just to be sure...

NiLuJe added a commit to NiLuJe/crengine that referenced this pull request Aug 19, 2018
I like it, but it's just way too expensive given how things are
implemented right now.

re koreader#230
@poire-z
Copy link
Contributor

poire-z commented Aug 19, 2018

These tests were in the original code, and I assume they are allright when I read this in freetype.h:

   *   By default, hinting is enabled and the font's native hinter (see
   *   @FT_FACE_FLAG_HINTER) is preferred over the auto-hinter.  You can
   *   disable hinting by setting @FT_LOAD_NO_HINTING or change the
   *   precedence by setting @FT_LOAD_FORCE_AUTOHINT.  You can also set
   *   @FT_LOAD_NO_AUTOHINT in case you don't want the auto-hinter to be
   *   used at all.

@poire-z
Copy link
Contributor

poire-z commented Aug 19, 2018

I really don't have an eye for catching what's wrong :) so take my comments for what they are :|

HarfBuzz, matching flags, AutoHint looks not like the previous to me, so not as good (me ans h er actu ally) which is the kind of strange things I noticed when testing and concluded that HarfBuzz and Auto hint = bad (that was on the emulator, it's not as bad on my Kobo).

And in both your HarfBuzz, matching flags, autohinter/native, with a FT linked against HB. the fr om in from a big list is worse than in others :|

It mostly looks better on eInk than on our computer screens. The only bothering thing on eInk are the occassional fat and stuck ss as in association.
edit: note that I mostly checked with a small font size

@NiLuJe
Copy link
Member Author

NiLuJe commented Aug 19, 2018

@poire-z : Yeah, except FT can be built with no native hinting support at all, and has a mind of its own as to whether it actually always do what you tell it to (mostly, when dealing with tricky fonts).

But, yeah, generally, nothing means native, but I tend to prefer being very very explicit when I want native hinting for sure ;).

I'll see if that makes any difference in this case, though ;).


HarfBuzz, matching flags, AutoHint is of course not exactly like FT alone, but it is much closer than without the flags ;).

HarfBuzz, matching flags, native, with a FT linked against HB is borked, for some reason, so, yeah, it's terrible ;).

The autohint variant, on the other hand, looks pretty damn good (and, specifically, that from might not look all that great, but it is identical to FT's version ;)).

@NiLuJe
Copy link
Member Author

NiLuJe commented Aug 19, 2018

Quick'n dirty visualisation w/ IM's compare tool (autohint in all cases).

FT to HB w/ Flags
ft_to_hb

FT to FT+HB
ft_to_fthb

FT to HB w/ flags w/ FT+HB
ft_to_full

@poire-z
Copy link
Contributor

poire-z commented Aug 21, 2018

^^ might need more proper arguments to the hb_font_set_scale() call. Dunno if the size*64 is enough or right :) there are more complex stuff, for example in:

https://github.com/harfbuzz/harfbuzz/issues/559

And it's unclear to me what hb_ft_font_set_funcs() does ...

@NiLuJe
Copy link
Member Author

NiLuJe commented Aug 21, 2018

Native:
pz_native

Auto:
pz_auto

@NiLuJe
Copy link
Member Author

NiLuJe commented Aug 21, 2018

It's not honoring FT advances at all, which is basically what using the hb_ft approach with the wrong flags does, as is shown by the comparison shots (perfect match in both cases) ;).

(i.e., it's using unhinted metrics).

HB to PZ (Auto)
hb_to_pz_auto

HB To PZ (Native)
hb_to_pz_native

@NiLuJe
Copy link
Member Author

NiLuJe commented Aug 21, 2018

Possibly a bit faster (I can still hear my CPU fan start to spin up ;p.) with the PR in, but it's apparently not perfect, so I'm not sure how viable that'd be.

@poire-z
Copy link
Contributor

poire-z commented Aug 21, 2018

(OK :| about my hb_font_create try, thanks for testing :)
With the harfbuzz PR: Just a bit faster ? So not worth it? But you got the results you liked?

@NiLuJe
Copy link
Member Author

NiLuJe commented Aug 21, 2018

@poire-z : I don't really have hard numbers since it was only spinning the CPU for a few seconds with only Noto Serif & Noto Sans being loaded ;).

So, faster, yeah, but I can't really quantify it ;).

Results were identical as without the PR, AFAICT, but I'll double-check.

@NiLuJe
Copy link
Member Author

NiLuJe commented Aug 21, 2018

Ah. If you look at the page, stuff renders indentically, but there might be something wonky going on somewhere, because positioning/line-spacing is going bonkers:

pr_auto

@NiLuJe
Copy link
Member Author

NiLuJe commented Aug 21, 2018

Take that w/ a grain of salt, as I moved that build to my base head, so that's HB 1.8.8 vs. 1.8.7 (... plus whatever else might have changed, since that was a from-scratch build from a newly bootstrapped checkout).

@NiLuJe
Copy link
Member Author

NiLuJe commented Aug 21, 2018

Yeah, the different spacing is the same with the other kerning methods, so, err, possibly because of something else that changed somewhere :D (Or I botched the CRe patch).

@poire-z
Copy link
Contributor

poire-z commented Aug 21, 2018

Well, with latest crengine master (so, including this PR and not the one that revert it), with HB 1.8.7 and freetype NOT rebuilt against harfuzz, with their 1082.patch and this patch to our base, after cleaning the harfbuzz build tree:

--- a/thirdparty/harfbuzz/CMakeLists.txt
+++ b/thirdparty/harfbuzz/CMakeLists.txt
@@ -15,10 +15,12 @@ assert_var_defined(FREETYPE_DIR)
 ep_get_source_dir(SOURCE_DIR)
 ep_get_binary_dir(BINARY_DIR)

+set(PATCH_CMD1 sh -c "patch -N -p1 < /tmp/1082.patch || true")
+
 set(CFG_ENV_VAR "CC=\"${CC}\" CXX=\"${CXX}\" CFLAGS=\"${CFLAGS}\" CXXFLAGS=\"${CXXFLAGS}\" LDFLAGS=\"${LDFLAGS}\"")
 set(CFG_ENV_VAR "${CFG_ENV_VAR} FREETYPE_CFLAGS=\"-I${FREETYPE_DIR}/include/freetype2\"")
 set(CFG_ENV_VAR "${CFG_ENV_VAR} FREETYPE_LIBS=\"-L${FREETYPE_DIR} -lfreetype\"")
-set(CFG_OPTS "--prefix=${BINARY_DIR} --enable-shared --disable-static --with-freetype --with-ucdn --without-glib --without-gobject --without-cairo --without-fontconfig --without-icu --without-graphite2 --without-uniscribe --without-directwrite --without-coretext --host=\"${CHOST}\"")
+set(CFG_OPTS "--prefix=${BINARY_DIR} --enable-shared --disable-static --with-freetype --with-ucdn --without-glib --without-gobject --without-cairo --without-fontconfig --without-icu --without-graphite2 --without-uniscribe --without-directwrite --without-coretext --enable-h_advance_cache --host=\"${CHOST}\"")
 set(CFG_CMD sh -c "${CFG_ENV_VAR} ${SOURCE_DIR}/configure ${CFG_OPTS}")

 ko_write_gitclone_script(
@@ -33,7 +35,7 @@ ExternalProject_Add(
     ${PROJECT_NAME}
     DOWNLOAD_COMMAND ${CMAKE_COMMAND} -P ${GIT_CLONE_SCRIPT_FILENAME}
     BUILD_IN_SOURCE 1
-    PATCH_COMMAND NOCONFIGURE=1 ./autogen.sh
+    PATCH_COMMAND COMMAND NOCONFIGURE=1 ./autogen.sh COMMAND ${PATCH_CMD1}
     CONFIGURE_COMMAND ${CFG_CMD}
     BUILD_COMMAND $(MAKE) -j${PARALLEL_JOBS} --silent
     INSTALL_COMMAND $(MAKE) -j${PARALLEL_JOBS} install

(not sure about the order of the patch commands...)

I get back the 13s render time !
If I just remove --enable-h_advance_cache, I get the 55s as before (65s on re-rendering)
No significant increase of memory usage after load, 133M without, 134M with, could be noise.
I haven't checked how the cache gets cleaned or release thus.

So, timing wise, harfbuzz PR 1082 helps a lot!

Now, it's for you to confirm you get the kerning/hinting as you expect/liked it with this PR not reverted (= the same as in your screenshots from 2 days ago).

@NiLuJe
Copy link
Member Author

NiLuJe commented Aug 22, 2018

Okay, I'm stupid, the spacing discrepancies were because... I had changed the spacing, and forgot to do that again on the new checkout :D.

@NiLuJe
Copy link
Member Author

NiLuJe commented Aug 22, 2018

Okay, tried again with matching settings on master, similar results, with a caveat:

Native hinting + harfbuzz shaping is borked when FT is NOT built against HB (for... some reason? That doesn't make sense, AFACT, FT+HB should only affect Auto).

(It's okay with FT kerning).

And, of course, an FT+HB build seems to slow things down some more with harfbuzz shaping...

EDIT: Conversely, with FT+HB, it's Auto that's weird, and doesn't match my previous results... -_-".

I'm also not feeling much speedup from the PR ;?

@NiLuJe
Copy link
Member Author

NiLuJe commented Aug 22, 2018

TL;DR: Meh?

I'll check again tomorrow without the PR, to see if I can match yesterday's results again.

@NiLuJe
Copy link
Member Author

NiLuJe commented Aug 22, 2018

Also, forgot to answer that: yep, wrong patching order: patch first, autoreconf/autogen later, especially here, with a patch affecting configure.ac ;)

@poire-z
Copy link
Contributor

poire-z commented Aug 22, 2018

wrong patching order: patch first, autreconf/autogen later

OK. It works as well with the right ordering.
(I indeed noticed 2 times the same kind of output while rebuilding - I guess the configure part noticed configure.ac has changed, and cleverly re-did the autogen part)

@poire-z
Copy link
Contributor

poire-z commented Aug 23, 2018

Just a note, in case we use 1082.patch, and unrevert the hb_ft_font_set_load_flags() calls and call them too in the setHinting() method: we'll have to add in that harfbuzz patch ft_font->advance_cache.clear() in the hb_ft_font_set_load_flags() function too.

@poire-z
Copy link
Contributor

poire-z commented Jan 2, 2019

@NiLuJe
Looks like something equivalent to the HB PR 1082 mentionned above has been made into HB 2.0.0:

https://github.com/harfbuzz/harfbuzz/pull/1082
https://github.com/harfbuzz/harfbuzz/commit/0f520adaacca3c7b6d8e84a7722343184105f612
https://github.com/harfbuzz/harfbuzz/commit/0ea42e117ba2c76e118974fe114ae5d9ceef5743
https://github.com/harfbuzz/harfbuzz/commit/d8a67dac2a673138bb4d41cd7eab97c9ee987958
https://github.com/harfbuzz/harfbuzz/commit/cbea7d49ab8d4765a2d72dcbf608d326bdf9af3d
https://github.com/harfbuzz/harfbuzz/commit/237f21537842e6b471cdd6c86b98edfc0da0756c
https://github.com/harfbuzz/harfbuzz/commit/047a84c5dd76cdfc072de25c572e30866f87a1f7
https://github.com/harfbuzz/harfbuzz/commit/f90bab8560816b60b4b3f2379b36c08756b21e6c
https://github.com/harfbuzz/harfbuzz/commit/54998befc43ef38e47b74b3153380adbcf6279d4
https://github.com/harfbuzz/harfbuzz/commit/383060cc3354e12611dec3082a6fe08fdb25f652

I just had a try with uncommenting the 2 // NOTE: Commented out for now, it's prohibitively expensive. c.f., #230 added in #231, and my test case from above loads in 13s instead of the 55s from some months ago. So, 13s with or without your FT load flags stuff.

So, you may want to revisit this again :)
(With possibly some more stuff like the one I mentionned at the bottom of #230 (comment) - I haven't re-read this whole issue :)

@NiLuJe
Copy link
Member Author

NiLuJe commented Jan 2, 2019

Yep, I noticed ;).

Haven't had time to check again, though. Plus, IIRC, for best results, we'd have to do the whole "we need FT built against HB" thing.

poire-z added a commit to poire-z/crengine that referenced this pull request Sep 25, 2019
Re-enable c02f597 (koreader#230) that was reverted by 330d7b1 (koreader#231), as the
performance hit as been fixed on Harfbuzz side by using caching.
Also re-init HB fonts on hinting mode change to clear HB's internal
caches (so we get reproducible renderings when changing hinting mode).
poire-z added a commit to poire-z/crengine that referenced this pull request Sep 25, 2019
Re-enable c02f597 (koreader#230) that was reverted by 330d7b1 (koreader#231), as the
performance hit has been fixed on Harfbuzz side by using caching.
Also re-init HB fonts on hinting mode change to clear HB's internal
caches (so we get reproducible renderings when changing hinting mode).
poire-z added a commit that referenced this pull request Sep 25, 2019
Re-enable c02f597 (#230) that was reverted by 330d7b1 (#231), as the
performance hit has been fixed on Harfbuzz side by using caching.
Also re-init HB fonts on hinting mode change to clear HB's internal
caches (so we get reproducible renderings when changing hinting mode).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants