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

Performance Issues Rendering Lots of Text #307

Closed
darkfrog26 opened this issue Oct 9, 2017 · 14 comments
Closed

Performance Issues Rendering Lots of Text #307

darkfrog26 opened this issue Oct 9, 2017 · 14 comments

Comments

@darkfrog26
Copy link

I'm not sure if this is just a limitation of the shear complexity of rendering text on the screen, but I'm getting fairly slow rendering of lots of text on the screen:

screenshot from 2017-10-09 12-30-01

It's taking around 250ms to render each time. I've tried converting it all to paths but it doesn't seem to help. Is this an expected performance limitation or is there something that can be done?

@axkibe
Copy link
Contributor

axkibe commented Oct 9, 2017

I've been rendering way more in way less time. ( see for example http://www.ideoloom.net/ )

However I'm caching glyphs in mini canvases and then paste them (a given glyph with a given size and color doesn't need to rendered twice)

@fpirsch
Copy link
Collaborator

fpirsch commented Oct 9, 2017

Hi @darkfrog26,
rendering text is very complex indeed. Opentype has not been designed as a fast rendering library (what for, anyway ?) but as a glyph and font manipulation tool. Things could be improved, though.

@darkfrog26
Copy link
Author

I'm building a framework that, I'm hoping, will be a viable alternative to using HTML, but everything is drawn in Canvas. The performance issues create serious problems with that being possible.

@fdb
Copy link
Contributor

fdb commented Oct 9, 2017

I suggest profiling to see which parts are slow (and then proposing a PR that fixes it ;-)).

As always, the solution will be caching. If you think about "normal" font rendering, the cache the glyphs of a specific font at a specific size in a texture atlas. If you want the same performance I think you will end up with a solution very similar to that.

Rendering a texture atlas from OpenType.js is out of scope, but I imagine you could build a library on top of OTjs...

@darkfrog26
Copy link
Author

The problem is, in the test I'm running I'm playing with a scenario that sets the fill of the text path to a video, so it needs to re-render with every video frame. Obviously this is a pretty crazy scenario, but I figured if I could get the performance good enough to do that then HTML can effectively be considered antiquated. :-p

Unfortunately, this means that caching isn't really an option apart from caching the paths. I have been considering using Path2D on browsers that support it, but I'm not sure if that will really offer much of a performance benefit over drawing the paths on-demand.

@darkfrog26
Copy link
Author

FYI, two changes in the way I deal with rendering paths increased performance from 250ms per render to 50ms:

1.) I removed all open and close path calls between letters so the entire block of text is represented by a single path.
2.) Utilize Path2D (https://developer.mozilla.org/en-US/docs/Web/API/Path2D) instead of raw instructions to canvas context (made a significant improvement per render).

Any other suggestions are appreciated, but 20 renders per second is pretty decent for the level of complexity I'm drawing (especially since I'm up-scaling rendering for retina displays, so it's rendering at twice the displayed size).

@axkibe
Copy link
Contributor

axkibe commented Oct 10, 2017

In case you want a video in the fill, how about just making a white/transparent cookie cutter of the whole text and apply it as "and-put" on each frame.

Heck you can even overlay two canvases, or a canvas above a <video> tag.

@axkibe
Copy link
Contributor

axkibe commented Oct 10, 2017

PS: the native type rendering libraries of your operating system do glyph and even word caching too. Also on the very first render of a new glyph aren't that fast either, native and canvas.drawText().

@fpirsch for me performance is important too, but as I said, opentype.js is very acceptable, if added some caching. Maybe some things can be improved, but IMO opentype.js is in the upper field of doable already anyway.

PPS: The reason why I switched to opentype.js from canvas.drawText() are unrepairable issue with textzooming there. First there is an upper limit in text size which makes unlimited zoom not possible. Secondly native canvas.drawText() adds fonthinting rounding errors to text propagation, while opentype.js can be changed for each letter to be rounded, but not add rounding decissions to following letters. (that is "oooooooooooooooo" and "oooooooooooooooo" in a slightly different font size can have suddendly vastly different total lengths)

@darkfrog26
Copy link
Author

@axkibe I'm not sure I understand the "cookie cutter" approach you're talking about...can you elaborate on how that would work?

@axkibe
Copy link
Contributor

axkibe commented Oct 10, 2017

Just make a transparent canvas above a video element. Or make two canvases atop each other one in which your text is transparent and the lower one behind with the animated content (however you want to animate it).

The web is full of examples that do this, it's simple CSS.

@darkfrog26
Copy link
Author

Ah, I see what you mean. Thanks. :)

@fpirsch
Copy link
Collaborator

fpirsch commented Oct 10, 2017

👍 for Path2D. Except that it only works in the browser, and it is not editable (remember OT.js is initialy a glyph edition library). Path2D could be used alongside the internal representation, just for rendering. But then memory could become an issue.

@darkfrog26
Copy link
Author

I understand, and I wasn't suggesting adding it to OpenType.js, but rather just as some feedback for anyone else looking to optimize their rendering. It's incredibly unclear based on online reading if Path2D offers much benefit, and I'm here to say that it definitely does!

@axkibe
Copy link
Contributor

axkibe commented Oct 11, 2017

Just wondering, what you want to do can also be done with conventional canvas.strokeText -- using the stroke for globalCompositeOperation = 'destination-out' to cut out transparency. For this there is no need for opentype.js

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

No branches or pull requests

4 participants