Open Bug 925651 Opened 11 years ago Updated 2 years ago

SVG-in-OpenType glyphs containing filters perform much worse than they should due to over-large surfaces

Categories

(Core :: SVG, defect)

defect

Tracking

()

People

(Reporter: jfkthame, Unassigned)

References

(Blocks 1 open bug, )

Details

(Keywords: perf)

Attachments

(1 file)

See testcase in URL field. The "cocktail" image in the testcase does not include any <filter> elements; it animates reasonably well, whether rendered as an <img> or as an SVG glyph within a webfont (though it does exercise my CPU pretty hard). Now compare results with the "beer" image, which does use <filter>s. This still animates OK when rendered as an <img>, but when switching to the SVG glyph rendering it becomes extremely slow/jerky -- I'm seeing no more than about 3-4 fps on my MacBook Pro. The issue is not specific to this particular image; I've seen similarly poor behavior with any SVG glyph that uses <filter>. Profiling confirms that we're spending most of the time in SVG filter code.
Are the filter bounds reasonable values?
I'm not sure what "reasonable" values should be (though they look sensible enough to me); you can check the source of http://people.mozilla.org/~jkew/opentype-svg/beer_mug.svg to see exactly what's in there.
The beer image does not actually do any filter drawing when used as <img>, if I can believe my profiler. I wonder why.
(In reply to Markus Stange [:mstange] from comment #3) > The beer image does not actually do any filter drawing when used as <img>, > if I can believe my profiler. I wonder why. Try setting a breakpoint, e.g. on nsSVGFilterInstance::Render. My debugger assures me that's getting hit plenty of times in the <img> case (as well as the glyph version). But in this case it seems to be quick enough that the profiler may not notice.
Assignee: nobody → mstange
Status: NEW → ASSIGNED
Keywords: perf
OS: Mac OS X → All
Hardware: x86 → All
Version: unspecified → Trunk
Filter rendering is slower with the glyph because we create much larger temporary surfaces. The surface size is determined in nsAutoFilterInstance::nsAutoFilterInstance, which looks at the scale factors of the canvasTM as returned by nsSVGUtils::GetCanvasTM(aTarget, nsISVGChildFrame::FOR_OUTERSVG_TM). In the testcase, these scale factors are 1 in the SVG image case and 40.625 in the glyph case. I haven't attempted to figure out where this large scale comes from. For that, a minimal WOFF test case would be very helpful.
Jonathan, do you have any tools to assist in creating WOFF files with SVG glyphs?
Flags: needinfo?(jfkthame)
You should be able to do this with Roc's tool[1] at https://github.com/rocallahan/svg-opentype-workshop. IIRC, you need to check out the code and then open your local copy, it's not set up for actual online use. [1] Well, you'll actually get .otf files, not .woff, but that doesn't matter.
Flags: needinfo?(jfkthame)
Flags: needinfo?(jwatt)
Attached patch patchSplinter Review
Using nsSVGUtils::GetCanvasTM() is completely wrong. We want to match the filter offscreens to the DrawTarget that we're drawing to. In the case of SVG inline in HTML where the HTML has a transform on it, using GetCanvasTM will also produce bad results. What we should really be using is nsFilterInstance::mPaintTransform. The only time that we end up in nsFilterInstance::ComputeUserSpaceToFilterSpaceScale is when we're under an nsFilterInstance::PaintFilteredFrame call, so mPaintTransform will be set.
Flags: needinfo?(jwatt)
Attachment #8536953 - Flags: review?(mstange)
(In reply to Jonathan Watt [:jwatt] from comment #9) > The only time that we end up in > nsFilterInstance::ComputeUserSpaceToFilterSpaceScale is when we're under an > nsFilterInstance::PaintFilteredFrame call Is that true? ComputeUserSpaceToFilterSpaceScale is called from the nsFilterInstance constructor, and there are other static nsFilterInstance methods that create an nsFilterInstance instance, e.g. those called from nsSVGIntegrationUtils::ComputePostEffectsVisualOverflowRect or nsSVGIntegrationUtils::AdjustInvalidAreaForSVGEffects. In those places we don't have the paint transform around. I suppose, in order to fix this properly, we'd have to drop the concept of a filter space completely and do all calculations in user space, and then only convert any units to layer pixels late during filter drawing, e.g. when creating FilterNodes in FilterSupport.cpp.
Attachment #8536953 - Flags: review?(mstange)
I'm just hanging out here 'cause :jfkthame said in bug 925651 this bug was the reason that svg fonts seem unusably slow judging from the demo page. So figured I'd wait to see if that was, in fact, the case. 'course if this bug languishes, I guess I could try stripping all filters from the testcase and seeing if SVG fonts are a reasonable thing to use at that point. ... 'course until more browsers support SVG fonts, use for them is mostly just novelty and minor enhancements.
Ack. Sorry... He said that in bug 1027467 (which is not dupe/depends)
It is now.
Blocks: 1027467
I'm not going to get to this soon. The basic problem is that we can't predict the CSS pixels to filter device pixels scale in advance. So we should stop trying, and only deal with values in (float) CSS pixels until we have a draw target. Then at the last moment, when we convert the FilterDescription to the gfx::FilterNodes, we can convert coordinates into filter space, with the right scale (derived from the DrawTarget's current transform).
Assignee: mstange → nobody
Status: ASSIGNED → NEW
See Also: → 1338393
Summary: poor performance of filters when used in SVG glyphs → SVG-in-OpenType glyphs containing filters perform much worse than they should due to over-large surfaces
Severity: normal → S3
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: