Closed Bug 458031 Opened 16 years ago Closed 16 years ago

Long (tall) DIVs using -moz-box-shadow with blur radius make Firefox run really slowly

Categories

(Core :: Web Painting, defect, P2)

defect

Tracking

()

VERIFIED FIXED
mozilla1.9.2a1

People

(Reporter: mail, Assigned: ventnor.bugzilla)

References

()

Details

(4 keywords)

Attachments

(3 files, 7 obsolete files)

User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b1pre) Gecko/20080929033431 Minefield/3.1b1pre Build Identifier: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b1pre) Gecko/20080929033431 Minefield/3.1b1pre Long (tall) DIV's using the -moz-box-shadow CSS3 hack make FF run really slow - scrolling down the page can take a long time and is very jerky. When the box shadow is removed then the problem no longer exists. I've added a 'max-height' to the page in question as a slight work-around but the page still renders very slowly. Reproducible: Always Steps to Reproduce: 1. create a div, say 1000px high or more 2. add -moz-box-shadow to the css for the div 3. view page and scroll up/down Actual Results: Very slow to scroll up/down - also causes css menu to work very slowly. shorter pages do not have this issue. Expected Results: nice smooth scrolling!
see also: http://www.sunbridgeroadmission.org.uk/?id=8 (ie it's not the photo's causing it to go slow!) Try page-up and page-down for a better idea.
I tested the menus (on Windows) because the scrolling was already bad since about August 2006, it only got worse. Depends also on what machine you test it. This regressed on 7 July 2008 and the most likely cause is Bug 212633 :).
Blocks: 212633
Component: General → Style System (CSS)
Product: Firefox → Core
QA Contact: general → style-system
Version: unspecified → Trunk
Flags: blocking1.9.1?
Summary: Long (tall) DIV's using the -moz-box-shadow CSS3 hack make FF run really slow → Long (tall) DIVs using -moz-box-shadow make Firefox run really slowly
Component: Style System (CSS) → Layout: View Rendering
QA Contact: style-system → layout.view-rendering
This is definitely due to the way we do box shadows, every time you scroll the 1000px div must be redrawn on the shadow context and blurred again, blurring is done on the CPU. I suppose we can somehow limit blurring to the dirty rect but I'm not sure how to perfect it.
It is not that bad on OS X, but scrolling is slower than the latest Fx 3.0x release.
OS: Windows XP → All
Hardware: PC → All
Status: UNCONFIRMED → NEW
Ever confirmed: true
Attached file testcase2
This test allows on/off switching of box-shadow. Bug doesn't effect shadows without blur radius.
Summary: Long (tall) DIVs using -moz-box-shadow make Firefox run really slowly → Long (tall) DIVs using -moz-box-shadow with blur radius make Firefox run really slowly
Assignee: nobody → ventnor.bugzilla
Flags: blocking1.9.1? → wanted1.9.1+
Attached patch Patch (obsolete) — Splinter Review
This patch will optimize how much the computer has to blur, by calculating a smaller rect that will still create the exact same blur result within the dirty rect. All box-shadow sites are now almost as smooth as butter, and I've tested it with a lot of sites that use box-shadow to deal with all the corner-cases I can think of (which is the reason this patch may be a little complex). The sooner we get hardware blur the better.
Attachment #350044 - Flags: superreview?(roc)
Attachment #350044 - Flags: review?(roc)
+ renderContext->SetFillRule(gfxContext::FILL_RULE_WINDING); Why do you need this? Why do you need to mess with the rounded corner stuff? It would seem to me that all you need to do here is compute a smaller temporary surface rectangle (which should not depend on the rounded corners), but the actual RoundedRectangle/Rectangle operation that draws the box we're to shadow does not need to change at all. In fact it seems to me the right thing to do would be to pass the dirty rect into the boxblur object and have that object do all the work to adjust the temporary surface size. That should be simpler and also make it possible for other blur users to take advantage of dirty-rect optimization.
Attached patch Patch 2 (obsolete) — Splinter Review
Ah yes, this approach works much better. Thanks Roc, I don't know what I was thinking with that old approach or why this one didn't occur to me...
Attachment #350044 - Attachment is obsolete: true
Attachment #350065 - Flags: superreview?(roc)
Attachment #350065 - Flags: review?(roc)
Attachment #350044 - Flags: superreview?(roc)
Attachment #350044 - Flags: review?(roc)
+ + // Only paint what's in the dirty rect + renderContext->NewPath(); + renderContext->Rectangle(dirtyGfxRect); + renderContext->Clip(); Don't do this. It's not necessary and could cause problems if the dirty rect is not pixel aligned.
Attached patch Patch 3 (obsolete) — Splinter Review
Removed that bit of code and also found another small way to make it slightly faster.
Attachment #350065 - Attachment is obsolete: true
Attachment #350688 - Flags: superreview?(roc)
Attachment #350688 - Flags: review?(roc)
Attachment #350065 - Flags: superreview?(roc)
Attachment #350065 - Flags: review?(roc)
Attachment #350688 - Flags: superreview?(roc)
Attachment #350688 - Flags: superreview+
Attachment #350688 - Flags: review?(roc)
Attachment #350688 - Flags: review+
As we discussed in real life, that clipping code is actually needed since we're not computing correct pixels for part of the shadow now, so we shouldn't try to draw them.
Attached patch Patch 4 (obsolete) — Splinter Review
Yeah, I was not only wondering why the clipping wasn't needed, but why removing it didn't seem to change behaviour.
Attachment #350688 - Attachment is obsolete: true
Attachment #350711 - Flags: superreview?(roc)
Attachment #350711 - Flags: review?(roc)
- shadowContext = blurringArea.Init(shadowRect, blurRadius, 1, renderContext); + shadowContext = blurringArea.Init(dirtyGfxRect, blurRadius, 1, renderContext); We should be intersecting shadowRect with dirtyGfxRect.
Attached patch Patch 5 (obsolete) — Splinter Review
No. If the dirty rect only intersects a blurred edge of the shadow (which shadowRect doesn't include) then it won't get painted. I have a screenshot if you don't understand or you're skeptical :) However, shadowRectPlusBlur is available and sounds like what you want.
Attachment #350711 - Attachment is obsolete: true
Attachment #350714 - Flags: superreview?(roc)
Attachment #350714 - Flags: review?(roc)
Attachment #350711 - Flags: superreview?(roc)
Attachment #350711 - Flags: review?(roc)
Yeah, I don't understand since the rectangle passed to blurringArea.Init is inflated by the blurRadius. Your shadowPaintRect.IsEmpty call would cause a problem if the intersection of the rectangles is empty, sure, so you should take it out. I guess the problem is that when the intersection of the rectangles is empty the rect's position becomes undefined. I reckon you should pass in the dirtyGfxRect as a parameter to blurringArea.Init so that it can inflate the shadowRect (effectively producing shadowRectPlusBlur) and then intersect with dirtyGfxRect. Then everyone's happy. Maybe nsContextBoxBlur can do the clipping to dirtyGfxRect too?
Attached patch Patch 6 (obsolete) — Splinter Review
I think this is how you wanted it.
Attachment #350714 - Attachment is obsolete: true
Attachment #350832 - Flags: superreview?(roc)
Attachment #350832 - Flags: review?(roc)
Attachment #350714 - Flags: superreview?(roc)
Attachment #350714 - Flags: review?(roc)
+ + gfxRect mDirtyRectIntersect; Add a comment explaining what this is. Actually I'd change the name to mRequiredShadowArea. + // Make sure its not EVEN_ODD like in some cases (box-shadow) and thus cause problems What does this mean? What you have here is correct, I think, but it produces temporary surfaces that are larger than necessary because gfxAlphaBlur outsets mDirtyRectIntersect by the blur radius but then does not intersect again with the shadow area.
Attached patch Patch 7 (obsolete) — Splinter Review
Addresses comments.
Attachment #350832 - Attachment is obsolete: true
Attachment #350851 - Flags: superreview?(roc)
Attachment #350851 - Flags: review?(roc)
Attachment #350832 - Flags: superreview?(roc)
Attachment #350832 - Flags: review?(roc)
+ // We need to find the rect which contains the pixels we want to return. + // This area could get slightly smaller still by intersecting this rect with rectWithBlur + // and make that the temp surface size, but that would require API changes + // which we won't do at this stage. This comment doesn't make sense because we *are* intersecting with rectWithBlur. How about just // Determine the area of the shadow we need. and then after blur.Init, // XXX the temporary surface will be the mRequiredShadowArea inflated by // blurRadius in each direction so that the required shadow pixels are computed // correctly. We could actually use a smaller temporary surface by observing // that where the temporary surface is outside the rectWithBlur, the pixel // values are guaranteed to be fully transparent, so we could intersect the // inflated mRequiredShadowArea with rectWithBlur to compute the temporary // surface area. But we're not doing that right now because it's a bit more // complex.
Attached patch Patch 8Splinter Review
Change the comment.
Attachment #350851 - Attachment is obsolete: true
Attachment #350859 - Flags: superreview?(roc)
Attachment #350859 - Flags: review?(roc)
Attachment #350851 - Flags: superreview?(roc)
Attachment #350851 - Flags: review?(roc)
Attachment #350859 - Flags: superreview?(roc)
Attachment #350859 - Flags: superreview+
Attachment #350859 - Flags: review?(roc)
Attachment #350859 - Flags: review+
I think we should actually file a followup bug, though, to fix that XXX comment. The way things are with this patch, when the entire shadow fits in the dirty rect (e.g. the object is entirely on the page), we'll always create a temporary surface which is the box inflated by 2*blurRadius in each direction. That's an annoying waste of work.
This fixes 466353 which is blocking, so this should be blocking
Flags: wanted1.9.1+ → blocking1.9.1+
Keywords: checkin-needed
Pushed ce72e9a5dca0 to trunk.
Status: NEW → RESOLVED
Closed: 16 years ago
Keywords: checkin-needed
Resolution: --- → FIXED
Whiteboard: [needs landing] → [needs 191 landing]
Michael, please do file that followup bug.
Pushed 7324e52b2415 to 1.9.1
Keywords: fixed1.9.1
Whiteboard: [needs 191 landing]
Target Milestone: --- → mozilla1.9.1b3
Verified with Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b3pre) Gecko/20081213 Shiretoko/3.1b3pre ID:20081213034757.
Blocks: 468018
There is still a noticeable lag on attachment 342806 [details] when using the scroll bar and shadow enabled. Can we do more perf improvements?
Target Milestone: mozilla1.9.1b3 → mozilla1.9.2a1
(In reply to comment #28) > There is still a noticeable lag on attachment 342806 [details] when using the scroll bar > and shadow enabled. Can we do more perf improvements? Will this be handled by bug 468018? As I can see the patch on it is already checked into trunk but the perf issues are still there with Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2a1pre) Gecko/20081213 Minefield/3.2a1pre ID:20081213020516
We probably just need to speed up gfxBlur with SSE or something. Can you file a separate bug for that?
(In reply to comment #30) > We probably just need to speed up gfxBlur with SSE or something. Can you file a > separate bug for that? Sure. It's bug 469589 now. Alfred has already verified it with 1.9.1b3. I can verify the perf improvements with Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2a1pre) Gecko/20081213 Minefield/3.2a1pre and on OS X. Setting flags accordingly. I would think that it's a good testcase for Litmus.
Status: RESOLVED → VERIFIED
Flags: in-litmus?
Component: Layout: View Rendering → Layout: Web Painting
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: