Open Bug 527386 Opened 15 years ago Updated 2 years ago

Canvas text functions are too slow

Categories

(Core :: Graphics: Canvas2D, defect)

defect

Tracking

()

People

(Reporter: tthomps, Unassigned)

References

()

Details

(Keywords: testcase)

Attachments

(8 files)

User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2b1) Gecko/20091029 Firefox/3.6b1 Build Identifier: The text functions of the 2d canvas -- measureText, fillText, strokeText, the font property, and drawing text shadows -- do not effectively scale to support drawing a large number of strings on the canvas at once. I am attaching a page that tests the performance of these canvas functions, and two images of the results on my machine, one for Firefox 3.6b1 and one for Safari 4. Reproducible: Always
Attached image Firefox 3.6b1 results (deleted) —
Attached image Safari 4 results (deleted) —
Attached file Speed test (deleted) —
Attached file Windows profile (deleted) —
One simple thing that can be done to improve speed is to change the space-replacement function. The current implementation looks like this: From nsCanvasRenderingContext2D.cpp: 2103 static inline void 2104 TextReplaceWhitespaceCharacters(nsAutoString& str) 2105 { 2106 str.ReplaceChar("\x09\x0A\x0B\x0C\x0D", PRUnichar(' ')); 2107 } It looks like ReplaceChar iterates through every character in the replace string ("\x09\x0A...") for each character in the input string, which is very inefficient. I think it would be good to use something like this instead: PRUnichar *c = str.BeginWriting(); PRUnichar *end = str.EndWriting(); for(; c < end; c++) { // replace WHATWG spaces, (0x09, 0x0A, 0x0C, 0x0D), with space char 0x20 if(*c >= 9 && *c <= 13) // if we want to include 0x0B *c = PRUnichar(' '); } The above function will replace 0x0B with +U0020 as the current code does, but I do want to note that the HTML5 specification currently doesn't include 0x0B as a character that should be replaced, unless I'm missing something. Alternatively something like these could be used: for(; c < end; c++) { if(*c == 0x09 || *c == 0x0A || *c == 0x0C || *c == 0x0D) *c = PRUnichar(' '); } Or.. const PRInt32 whatwgSpace [] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0 }; for(; c < end; c++) { if(*c < 14) if(whatwgSpace[*c]) *c = PRUnichar(' '); }
I've only done a simple runtime profile at this point, which is shown in the "Windows profile" attachment. Since it's only a measure of exported functions, it does not give the complete picture of cpu usage here, since a lot of the issues appear to be in internal code. It does look like some functions, such as UpdateFontList, could be improved a bit to gain some speed.
Another thing of note is that when text is drawn with strokeText or with a shadow, the call to Redraw is not given a bounding box for the operation: 2477 if (aOp == nsCanvasRenderingContext2D::TEXT_DRAW_OPERATION_FILL && !doDrawShadow) 2478 return Redraw(mThebes->UserToDevice(boundingBox)); 2479 2480 return Redraw();
Severity: enhancement → major
Attached image Firefox 3.6.4 results (deleted) —
Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.4) Gecko/20100413 Firefox/3.6.4 Safe Mode, freshly-open, 1 tab only, XP SP3, AMD Athlon XP 2600+, 1,92 Ghz, 1 GB RAM
Attached image Opera 10.51 results (deleted) —
Opera 10.51 results on same machine as above.
This bug also affects http://kothic.org/js/ in-browser map renderer - it is much slower in Firefox than in any other browser.
Attached image KothicJS rendering screenshot (deleted) —
When run in Firefox, KothicJS spends most of its time rendering text on canvas. The result is ≈5 seconds of additional lag per each OpenStreetMap tile.
A JS application I’ve made for Chrome is unusable in Firefox due to this problem.
Jeff, Bas, would you take a look please? What I see so far on Mac is that the "shadow" case is ludicrously slow...
Status: UNCONFIRMED → NEW
Ever confirmed: true
On my Mac, every test case is slower in Firefox than Chrome. While the 'shadow' case is some 300 times slower on Firefox, 'strokeText' is still some 17 times slower. 'fillRect' is the only test that gives similar results. FireFox Mac: 217ms, 1405ms, 737ms, 2720ms, 10670ms, 208ms. Chrome Mac: 213ms, 571ms, 156ms, 1291ms, 38ms, 13ms.
Blocks: 934525
All numbers are ms per frame Nightly 35 (Win 7 - Intel - D3D11 - OMTC - D2D 1.1) fillRect 1 fillText 47 measureText 16 font Property 71 shadow 365 strokeText 381 Firefox 32 (Win 7 - Intel - D3D10) fillRect 2 fillText 42 measureText 13 font Property 60 shadow 359 strokeText 356 Chrome 37 fillRect 6 fillText 8 measureText 3 font Property 12 shadow 10 strokeText 8 Chrome 38 fillRect 1 fillText 6 measureText 4 font Property 10 shadow 10 strokeText 7
On Nightly, at least with the backend on my platform, these numbers are within a few ms of Chrome with the exception of strokeText. I had a look at resolving that perf issue, but: CanvasRenderingContext2D.cpp:3492 has a note about CoreGraphics performance requiring individual glyphs to be sent off to the rendering backends (for all backends!), yet removing that and sending the whole buffer made it slower. Moved on to look at gfx/2d/DrawTargetCairo.cpp and tried cairo_glyph_path with the whole string buffer and that is even slower… it seems like this is blocked by Cairo performance improvements. Nightly 38 (Linux - nvidia - OMTC-off - cairo) fillRect 0 fillText 6 measureText 3 font Property 13 shadow 20 strokeText 950 OMTC appears to slow strokeText to ~1400ms Chrome 40 fillRect 0 fillText 2 measureText 1 font Property 5 shadow 4 strokeText 4
When I use skia instead of cario(change gfx.canvas.azure.backends), the time of strokeText is boost up. nightly 39, linux, nvidia, omtc-off cario: fillRect 1 fillText 7 measureText 4 font Property 14 shadow 19 strokeText 479 skia: fillRect 1 fillText 7 measureText 4 font Property 14 shadow 28 strokeText 40 chrome 40: fillRect 0 fillText 3 measureText 2 font Property 5 shadow 5 strokeText 4

Performance is still noticeably slower than Chrome: https://jsperf.com/canvas-text-performance

QA Whiteboard: qa-not-actionable
Attached image windows.png (deleted) —

Here's an anecdotal test: Windows: noticeably

  • shadow takes approx 60x times longer
  • strokeText approx 25x
  • fillText/font property approx 4x

In the process of migrating remaining bugs to the new severity system, the severity for this bug cannot be automatically determined. Please retriage this bug using the new severity system.

Severity: major → --
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: