Bug 102557

Summary: Adding occlusion detection to reduce overdraw in RenderBox background rendering
Product: WebKit Reporter: Justin Novosad <junov>
Component: New BugsAssignee: Justin Novosad <junov>
Status: RESOLVED FIXED    
Severity: Normal CC: cmarcelo, dglazkov, eric, fmalita, japhet, jbadics, macpherson, menard, ojan, senorblanco, simon.fraser, tomhudson, webkit.review.bot, zan
Priority: P2    
Version: 528+ (Nightly build)   
Hardware: Unspecified   
OS: Unspecified   
Attachments:
Description Flags
Patch
none
Patch
none
Patch
none
Patch
none
Patch for landing
none
Patch
none
Patch for landing none

Description Justin Novosad 2012-11-16 13:53:22 PST
Adding occlusion detection to reduce overdraw in RenderBox background rendering
Comment 1 Justin Novosad 2012-11-16 14:07:51 PST
Created attachment 174758 [details]
Patch
Comment 2 WebKit Review Bot 2012-11-16 16:44:51 PST
Comment on attachment 174758 [details]
Patch

Attachment 174758 [details] did not pass chromium-ews (chromium-xvfb):
Output: http://queues.webkit.org/results/14861375

New failing tests:
fast/dom/shadow/shadow-dom-event-dispatching.html
Comment 3 Brent Fulgham 2012-11-18 21:51:17 PST
Comment on attachment 174758 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=174758&action=review

Looks likea great change, but I was curious about the static cast switch rather than a simple virtual method. They all appear to be children of a common superclass.

> Source/WebCore/css/CSSImageGeneratorValue.cpp:200
> +{

In the ChangeLog could you indicate why this switch statement is preferable to a virtual method on CSSImageGeneratorValue? Seems like a lot of casting and specialized knowledge about which subclasses need this behavior. Was this found to be a bottleneck?
Comment 4 Justin Novosad 2012-11-19 12:36:54 PST
(In reply to comment #3)
> (From update of attachment 174758 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=174758&action=review
> 
> Looks likea great change, but I was curious about the static cast switch rather than a simple virtual method. They all appear to be children of a common superclass.

Actually, I was curious about that too when I wrote it.  I just followed the pattern that was already there.  I plead guilty to cargo cult programming.

I assume there is some sort of requirement for CSS*Value classes to be POD?  I should go satisfy my own curiosity, and come back...

FWIW, before landing this I will perform some experiments just to make sure we are getting full use case coverage (all the hasAlpha methods returning true and false).  I will add additional tests to the patch if needed.
Comment 5 Justin Novosad 2012-11-20 07:07:28 PST
(In reply to comment #3)
> 
> In the ChangeLog could you indicate why this switch statement is preferable to a virtual method on CSSImageGeneratorValue? Seems like a lot of casting and specialized knowledge about which subclasses need this behavior. Was this found to be a bottleneck?

The reason is already documented in CSSValue.h:
// NOTE: This class is non-virtual for memory and performance reasons.
// Don't go making it virtual again unless you know exactly what you're doing!
Comment 6 Justin Novosad 2012-11-21 13:03:46 PST
Created attachment 175503 [details]
Patch
Comment 7 Justin Novosad 2012-11-21 13:57:47 PST
Latest patch fixes issues I found while performing more in-depth testing.  I found that hasAlpha was returning true for opaque bitmap images that had not yet been pulled into cache.  To fix this, I had to add a RanderObject* argument to hasAlpha so that if the style contains a BitmapImage, the bitmap can be resolved for the current renderer.

The new patch also adds a layout test that covers a series of use cases that are optimization candidates.  The current patch successfully optimizes 6 of the 10 cases.  A regular test run does not verify that occlusion culling kicked in. To determine whether an optimization is successful, the test has to be run manually with a debugger attached.
Comment 8 Justin Novosad 2012-11-21 14:07:57 PST
Created attachment 175520 [details]
Patch
Comment 9 Justin Novosad 2012-11-21 14:08:57 PST
New patch adds test expectations for missing baselines
Comment 10 Build Bot 2012-11-21 18:53:33 PST
Comment on attachment 175520 [details]
Patch

Attachment 175520 [details] did not pass mac-ews (mac):
Output: http://queues.webkit.org/results/14961191

New failing tests:
fast/backgrounds/background-opaque-images-over-color.html
Comment 11 Justin Novosad 2012-11-22 08:55:45 PST
Created attachment 175684 [details]
Patch
Comment 12 Justin Novosad 2012-11-22 09:05:03 PST
New patch adds text baseline and fixes bug where "space" repeat mode was falsely considered opaque (bug caught by existing test).
Comment 13 Stephen White 2012-11-22 10:36:24 PST
Comment on attachment 175520 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=175520&action=review

> Source/WebCore/loader/cache/CachedImage.cpp:478
> +bool CachedImage::hasAlpha(const RenderObject* renderer)

Maybe we should rename this to currentFrameHasAlpha() as well, just to be clear to callers.
Comment 14 Stephen White 2012-11-22 10:40:18 PST
Comment on attachment 175520 [details]
Patch

Fix the above on landing, and I'm good with it.  r=me
Comment 15 Stephen White 2012-11-22 10:42:46 PST
Comment on attachment 175684 [details]
Patch

r+'ing the right patch this time.
Comment 16 Justin Novosad 2012-11-22 10:52:16 PST
Created attachment 175695 [details]
Patch for landing
Comment 17 Stephen White 2012-11-22 15:32:07 PST
Comment on attachment 175695 [details]
Patch for landing

According to Noel Gordon, the change to BitmapImage will break deferred image decoding.  See http://trac.webkit.org/changeset/125154

I'm going to cq- this patch for now until we can sort this out.
Comment 18 Justin Novosad 2012-11-23 07:15:56 PST
Created attachment 175805 [details]
Patch
Comment 19 Justin Novosad 2012-11-23 07:25:22 PST
Triggering the decode for the purpose of occlusion culling while rendering the RenderBox is perfectly fine because the decoded image will be required imminently anyways in order to draw it. New patch reverts change to BimapImage, and moves the decode triggering into CachedImage.  Since this is a new method, it won't affect previously existing code paths that check for the presence of alpha.
Comment 20 Stephen White 2012-11-23 08:44:06 PST
Comment on attachment 175805 [details]
Patch

Great.  This is the solution I was thinking of as well.  r=me
Comment 21 Build Bot 2012-11-23 09:08:45 PST
Comment on attachment 175805 [details]
Patch

Attachment 175805 [details] did not pass mac-ews (mac):
Output: http://queues.webkit.org/results/14966761

New failing tests:
fast/backgrounds/background-opaque-images-over-color.html
Comment 22 Justin Novosad 2012-11-23 09:42:51 PST
Created attachment 175821 [details]
Patch for landing
Comment 23 WebKit Review Bot 2012-11-23 10:44:35 PST
Comment on attachment 175821 [details]
Patch for landing

Clearing flags on attachment: 175821

Committed r135629: <http://trac.webkit.org/changeset/135629>
Comment 24 WebKit Review Bot 2012-11-23 10:44:40 PST
All reviewed patches have been landed.  Closing bug.
Comment 25 Simon Fraser (smfr) 2012-11-23 11:20:28 PST
Comment on attachment 175821 [details]
Patch for landing

View in context: https://bugs.webkit.org/attachment.cgi?id=175821&action=review

I wish I'd had a chance to review this before it was landed.

> Source/WebCore/loader/cache/CachedImage.cpp:482
> +    if (image->isBitmapImage())
> +        image->nativeImageForCurrentFrame(); // force decode

Seem unfortunate to force a decode here. Would that decode have always happened anyway, or would it be better to just say that it has alpha?

> Source/WebCore/loader/cache/CachedImage.h:55
> +    bool currentFrameHasAlpha(const RenderObject*); // Side effect: ensures decoded image is in cache, therefore should only be called when about to draw the image.

Why is this not const?

> Source/WebCore/rendering/RenderBox.cpp:1007
> +    // RenderBoxModelOBject::paintFillLayerExtended. A more efficient solution might be to move

Typo: OBject

> Source/WebCore/rendering/RenderBox.cpp:1012
> +    if (fillLayer->next() && (!fillLayer->hasOpaqueImage(this) || !fillLayer->image()->canRender(this, style()->effectiveZoom()) || !fillLayer->hasRepeatXY()))
> +        paintFillLayers(paintInfo, c, fillLayer->next(), rect, bleedAvoidance, op, backgroundObject);
>      paintFillLayer(paintInfo, c, fillLayer, rect, bleedAvoidance, op, backgroundObject);

I don't see how this correctly handles background-clip (which means the image might not fill the entire border box).

> Source/WebCore/rendering/RenderBoxModelObject.cpp:913
> +    if (!bgLayer->next() && !(shouldPaintBackgroundImage && bgLayer->hasOpaqueImage(this) && bgLayer->hasRepeatXY())) {

Same here.

> LayoutTests/ChangeLog:13
> +        * fast/backgrounds/background-opaque-images-over-color-expected.txt: Added.
> +        * fast/backgrounds/background-opaque-images-over-color.html: Added.
> +        * platform/chromium/TestExpectations:

Why was this not a ref tests? Without pixel results, the test is useless.
Comment 26 Justin Novosad 2012-11-23 11:36:17 PST
(In reply to comment #25)
> (From update of attachment 175821 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=175821&action=review
> 
> I wish I'd had a chance to review this before it was landed.

Noted, and don't worry I'll post a follow-up patch to address your concerns early next week.

> 
> > Source/WebCore/loader/cache/CachedImage.cpp:482
> > +    if (image->isBitmapImage())
> > +        image->nativeImageForCurrentFrame(); // force decode
> 
> Seem unfortunate to force a decode here. Would that decode have always happened anyway, or would it be better to just say that it has alpha?

Yes, a decode will happen anyways because this method is only ever called immediately before drawing the image.  I documented this side-effect in the header in case anyone else is tempted to use this method for other purposes.
> 
> 
> > Source/WebCore/rendering/RenderBox.cpp:1012
> > +    if (fillLayer->next() && (!fillLayer->hasOpaqueImage(this) || !fillLayer->image()->canRender(this, style()->effectiveZoom()) || !fillLayer->hasRepeatXY()))
> > +        paintFillLayers(paintInfo, c, fillLayer->next(), rect, bleedAvoidance, op, backgroundObject);
> >      paintFillLayer(paintInfo, c, fillLayer, rect, bleedAvoidance, op, backgroundObject);
> 
> I don't see how this correctly handles background-clip (which means the image might not fill the entire border box).

OK, I'm surprised no existing test picked-up on that 
I'll come-up with a layout test and a fix for that ASAP.

> 
> > LayoutTests/ChangeLog:13
> > +        * fast/backgrounds/background-opaque-images-over-color-expected.txt: Added.
> > +        * fast/backgrounds/background-opaque-images-over-color.html: Added.
> > +        * platform/chromium/TestExpectations:
> 
> Why was this not a ref tests? Without pixel results, the test is useless.

It is, I just submitted it without the pixel baselines.  I'll pick-up and submit the baselines from the bots with Tools/Script/webkit-patch garden-o-matic
Comment 27 Simon Fraser (smfr) 2012-11-23 11:50:27 PST
(In reply to comment #26)
> > > LayoutTests/ChangeLog:13
> > > +        * fast/backgrounds/background-opaque-images-over-color-expected.txt: Added.
> > > +        * fast/backgrounds/background-opaque-images-over-color.html: Added.
> > > +        * platform/chromium/TestExpectations:
> > 
> > Why was this not a ref tests? Without pixel results, the test is useless.
> 
> It is, I just submitted it without the pixel baselines.  I'll pick-up and submit the baselines from the bots with Tools/Script/webkit-patch garden-o-matic

A ref tests would have a -expected.html, and no .txt file.
Comment 28 Zan Dobersek 2012-11-24 03:25:21 PST
(In reply to comment #27)
> (In reply to comment #26)
> > > > LayoutTests/ChangeLog:13
> > > > +        * fast/backgrounds/background-opaque-images-over-color-expected.txt: Added.
> > > > +        * fast/backgrounds/background-opaque-images-over-color.html: Added.
> > > > +        * platform/chromium/TestExpectations:
> > > 
> > > Why was this not a ref tests? Without pixel results, the test is useless.
> > 
> > It is, I just submitted it without the pixel baselines.  I'll pick-up and submit the baselines from the bots with Tools/Script/webkit-patch garden-o-matic
> 
> A ref tests would have a -expected.html, and no .txt file.

Please make this a reftest unless it's absolutely necessary to test the generated render tree. It's easier for everyone to maintain a reference output of a 200x100px green rectangle than to potentially have many ports generate unneeded pixel baselines.

OTOH, the test is producing a text failure on every port (except mac where the test is skipped).
http://test-results.appspot.com/dashboards/flakiness_dashboard.html#group=%40ToT%20-%20webkit.org&tests=fast%2Fbackgrounds%2Fbackground-opaque-images-over-color.html
Comment 29 János Badics 2012-11-26 01:43:12 PST
Unfortunately, new fast/backgrounds/background-opaque-images-over-color.html started to fail on Qt. I have created a bug for the issue at

https://bugs.webkit.org/show_bug.cgi?id=103227

I will skip this test on Qt until it's fixed, if you don't mind.
Comment 30 János Badics 2012-11-26 02:50:02 PST
The test has been skipped on Qt in
http://trac.webkit.org/changeset/135698

Please unskip it with the proper fix

(see the related bug at
https://bugs.webkit.org/show_bug.cgi?id=103227 )
Comment 31 Simon Fraser (smfr) 2012-11-26 10:16:47 PST
I think we should revert this change if we don't get a fix soon.
Comment 32 Justin Novosad 2012-11-26 11:00:52 PST
Follow-ups:

Ref test:
https://bugs.webkit.org/show_bug.cgi?id=103275


Clip issue:
https://bugs.webkit.org/show_bug.cgi?id=103276