Bug 78549 - [Chromium] New CCOcclusionTracker class with tests
Summary: [Chromium] New CCOcclusionTracker class with tests
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: New Bugs (show other bugs)
Version: 528+ (Nightly build)
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Dana Jansens
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-02-13 16:20 PST by Dana Jansens
Modified: 2012-02-22 19:05 PST (History)
10 users (show)

See Also:


Attachments
Patch (84.98 KB, patch)
2012-02-13 16:31 PST, Dana Jansens
no flags Details | Formatted Diff | Diff
Patch (84.27 KB, patch)
2012-02-14 15:21 PST, Dana Jansens
no flags Details | Formatted Diff | Diff
Patch (103.79 KB, patch)
2012-02-16 20:17 PST, Dana Jansens
no flags Details | Formatted Diff | Diff
Patch (100.54 KB, patch)
2012-02-21 19:58 PST, Dana Jansens
no flags Details | Formatted Diff | Diff
Patch for landing (100.54 KB, patch)
2012-02-22 07:34 PST, W. James MacLean
no flags Details | Formatted Diff | Diff
Patch for landing (100.54 KB, patch)
2012-02-22 10:00 PST, W. James MacLean
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Dana Jansens 2012-02-13 16:20:02 PST
[Chromium] New CCOcclusionTracker class with tests
Comment 1 Dana Jansens 2012-02-13 16:31:19 PST
Created attachment 126861 [details]
Patch

Create the CCOcclusionTracker object, along with unit tests to verify its functionality.

The object encapsulates the logic of CCLayerTreeHost's paint culling, and CCQuadCuller's draw culling together in an object that can be used for both scenarios.

It tracks occlusion within the target surface, and within screen space. You can do a simple occluded() true/false test, or give it a rect in content space, and it
will return a sub-rect that contains all the unoccluded parts (in both the target surface and screen space) of the original rect.
Comment 2 Dana Jansens 2012-02-13 18:09:18 PST
Comment on attachment 126861 [details]
Patch

For @wjmaclean review
Comment 3 W. James MacLean 2012-02-14 13:59:46 PST
Overall comments: 

Generally, looks good.

I've heard some murmurings that "RenderSurfaces" could be on the road to extinction. Best to find out if that's true, and how (if at all) it will affect this CL.

It seems expensive computing both both "Screen-then-Target-surface, or Target-surface-then-Screen" in unoccluded{Surface}ContentRect. Is there no way to avoid this and predict the correct (conservative) occlusion in advance?

> Source/WebCore/platform/graphics/chromium/cc/CCOcclusionTracker.h
>
> 43 template<typename RenderSurfaceType> void enterTargetRenderSurface(RenderSurfaceType* newTarget);
> 44    template<typename RenderSurfaceType> void leaveToTargetRenderSurface(RenderSurfaceType* newTarget);

Seems awkward ... seems like they're the same, just the second assumes we're already in a target surface? Or are the names just misleading?

> 51 template<typename LayerType> bool occluded(LayerType*, const IntRect& contentRect) const;
> 52    // Gives an unoccluded sub-rect of |contentRect| in the content space of the layer. Used when considering occlusion for a layer that paints/draws something.

Comment doesn't seem to match.

> 65    FloatQuad transformedBoundsQuad = transform.mapQuad(FloatQuad(centeredBounds));
> 66    if (!transformedBoundsQuad.isRectilinear())
> 67        return Region();

Add comment specifying what transform types will lead to rectilinear bounds.

> 118    // Scale from content space to layer space
> 119    transform.scaleNonUniform(boundsInLayerSpace.width() / static_cast<double>(boundsInContentSpace.width()),
> 120                              boundsInLayerSpace.height() / static_cast<double>(boundsInContentSpace.height()));

Can this potentially fail for non-trivial transforms? E.g. rotation? Or is the transform from content to layer space always assumed to be translation + scale?I.e., how do we know when this is safe or is it always? Ditto for similar computations below.

Nice occlusion diagrams :-)
Comment 4 Dana Jansens 2012-02-14 15:09:53 PST
(In reply to comment #3)
> Overall comments: 
> 
> Generally, looks good.

Thanks!

> I've heard some murmurings that "RenderSurfaces" could be on the road to extinction. Best to find out if that's true, and how (if at all) it will affect this CL.

They are getting layers so that we don't have all this layer-like state on a RenderSurface. In this case, it will change the loops which call CCOcclusion tracker, and clean them up some hopefully. The CCOcclusionTracker should be minimally affected, mostly in the transform calculation functions.

> It seems expensive computing both both "Screen-then-Target-surface, or Target-surface-then-Screen" in unoccluded{Surface}ContentRect. Is there no way to avoid this and predict the correct (conservative) occlusion in advance?

Described it to @vollick briefly and he helped me see I can return the Rect for screen and target, and just take the intersection back in content space. This passes the unit tests for these functions that are somewhat particular, so it will be accurate enough. Thanks.

> > Source/WebCore/platform/graphics/chromium/cc/CCOcclusionTracker.h
> >
> > 43 template<typename RenderSurfaceType> void enterTargetRenderSurface(RenderSurfaceType* newTarget);
> > 44    template<typename RenderSurfaceType> void leaveToTargetRenderSurface(RenderSurfaceType* newTarget);
> 
> Seems awkward ... seems like they're the same, just the second assumes we're already in a target surface? Or are the names just misleading?

The first is done when we see a new layer. It says "hey we're in this target surface (if we weren't already)". The second is done when we see a contributing layer. It says "hey we were in this target surface but now we're done with it, and moving up to its parent". It's a merge-up operation. I'll add comments.

> > 51 template<typename LayerType> bool occluded(LayerType*, const IntRect& contentRect) const;
> > 52    // Gives an unoccluded sub-rect of |contentRect| in the content space of the layer. Used when considering occlusion for a layer that paints/draws something.
> 
> Comment doesn't seem to match.

The comment matches the function below it. I'll add one for occluded() too.

> > 65    FloatQuad transformedBoundsQuad = transform.mapQuad(FloatQuad(centeredBounds));
> > 66    if (!transformedBoundsQuad.isRectilinear())
> > 67        return Region();
> 
> Add comment specifying what transform types will lead to rectilinear bounds.

done.

> > 118    // Scale from content space to layer space
> > 119    transform.scaleNonUniform(boundsInLayerSpace.width() / static_cast<double>(boundsInContentSpace.width()),
> > 120                              boundsInLayerSpace.height() / static_cast<double>(boundsInContentSpace.height()));
> 
> Can this potentially fail for non-trivial transforms? E.g. rotation? Or is the transform from content to layer space always assumed to be translation + scale?I.e., how do we know when this is safe or is it always? Ditto for similar computations below.

content<->layer space is only a scale.

> Nice occlusion diagrams :-)
Comment 5 Dana Jansens 2012-02-14 15:21:46 PST
Created attachment 127055 [details]
Patch

For @enne review.
Comment 6 Dana Jansens 2012-02-16 20:17:54 PST
Created attachment 127505 [details]
Patch

- make pointers const all over
- add the CSS filter stuff that was added to CCLayerTreeHost, and unit test for it!
- add finishedTargetRenderSurface() to do cleanup/processing for the surface once all layers have been visited in it.
- add surfaceOccluded() which tells if part of the surface is occluded (by things outside the surface), and unit tests for this!

and..
- add currentOcclusionInScreenSpace() and currentOcclusionInTargetSpace() temporarily to make transition CLs easier.
Comment 7 Adrienne Walker 2012-02-21 19:00:12 PST
Comment on attachment 127505 [details]
Patch

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

So, this is just a patch to land independent functionality and then you'll land another patch to transition to switch over to using this?

Yay, for lots of tests.  :)

> Source/WebCore/platform/graphics/chromium/cc/CCOcclusionTracker.cpp:210
> +    if (!transformedQuad.isRectilinear())
> +        return false;
> +    return occlusion.contains(transformedQuad.enclosingBoundingBox());

Why the conditional? Even if not rectilinear, if the occlusion still contains the enclosing bounding box, then this contentRect is still occluded, yeah?

> Source/WebCore/platform/graphics/chromium/cc/CCOcclusionTracker.cpp:275
> +    // The use of enclosingIntRect, with floating point rounding, can give us a result that is not a sub-rect of contentRect. Shrink the result
> +    // down so that contentRect contains the result we return.
> +    int x = max(unoccludedRect.x(), contentRect.x());
> +    int y = max(unoccludedRect.y(), contentRect.y());
> +    int maxX = min(unoccludedRect.maxX(), contentRect.maxX());
> +    int maxY = min(unoccludedRect.maxY(), contentRect.maxY());
> +    return IntRect(x, y, maxX - x, maxY - y);

Why not just unoccludedRect.intersect(contentRect)?

> Source/WebCore/platform/graphics/chromium/cc/CCOcclusionTracker.cpp:297
> +IntRect CCOcclusionTrackerBase::surfaceUnoccludedContentRect(const LayerType* layer, const IntRect& surfaceContentRect) const

Where is this function going to get used? The other functions seem like a mirror of existing functionality in paint culling, but this and surfaceOccluded seems new and I'm not sure where they fit in the culling algorithm.

Also, can you write a test for this function that does more than take in a rect and spit the same rect back out?

> Source/WebCore/platform/graphics/chromium/cc/CCOcclusionTracker.h:80
> +    typedef void RenderSurfaceVoidType;
> +
> +    struct StackObject {
> +        const RenderSurfaceVoidType* surface;

Along with the fact that a pair of types gets used consistently across all these functions, this piece of code says to me really says that your class should be templated.  Maybe I'm missing something, but I don't see a need for void pointer shenanigans.

Also, if the class were templated, you could just typedef CCOcclusionTracker(Impl) rather than adding boilerplate functions that thunk through.
Comment 8 Adrienne Walker 2012-02-21 19:47:36 PST
Comment on attachment 127505 [details]
Patch

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

>> Source/WebCore/platform/graphics/chromium/cc/CCOcclusionTracker.cpp:297
>> +IntRect CCOcclusionTrackerBase::surfaceUnoccludedContentRect(const LayerType* layer, const IntRect& surfaceContentRect) const
> 
> Where is this function going to get used? The other functions seem like a mirror of existing functionality in paint culling, but this and surfaceOccluded seems new and I'm not sure where they fit in the culling algorithm.
> 
> Also, can you write a test for this function that does more than take in a rect and spit the same rect back out?

Oops, line 870 does have a such a test.  My bad.
Comment 9 Dana Jansens 2012-02-21 19:53:25 PST
(In reply to comment #7)
> (From update of attachment 127505 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=127505&action=review
> 
> So, this is just a patch to land independent functionality and then you'll land another patch to transition to switch over to using this?

Precisely. I'll make sure it's at feature-parity with any changes 'upstream' as I use it to replace existing code, and verify that any unit tests removed have the same cases covered for this class as I go.

> Yay, for lots of tests.  :)
> 
> > Source/WebCore/platform/graphics/chromium/cc/CCOcclusionTracker.cpp:210
> > +    if (!transformedQuad.isRectilinear())
> > +        return false;
> > +    return occlusion.contains(transformedQuad.enclosingBoundingBox());
> 
> Why the conditional? Even if not rectilinear, if the occlusion still contains the enclosing bounding box, then this contentRect is still occluded, yeah?

Yep! Thanks.

> > Source/WebCore/platform/graphics/chromium/cc/CCOcclusionTracker.cpp:275
> > +    // The use of enclosingIntRect, with floating point rounding, can give us a result that is not a sub-rect of contentRect. Shrink the result
> > +    // down so that contentRect contains the result we return.
> > +    int x = max(unoccludedRect.x(), contentRect.x());
> > +    int y = max(unoccludedRect.y(), contentRect.y());
> > +    int maxX = min(unoccludedRect.maxX(), contentRect.maxX());
> > +    int maxY = min(unoccludedRect.maxY(), contentRect.maxY());
> > +    return IntRect(x, y, maxX - x, maxY - y);
> 
> Why not just unoccludedRect.intersect(contentRect)?

Oh, duh.. thank you :)

> > Source/WebCore/platform/graphics/chromium/cc/CCOcclusionTracker.cpp:297
> > +IntRect CCOcclusionTrackerBase::surfaceUnoccludedContentRect(const LayerType* layer, const IntRect& surfaceContentRect) const
> 
> Where is this function going to get used? The other functions seem like a mirror of existing functionality in paint culling, but this and surfaceOccluded seems new and I'm not sure where they fit in the culling algorithm.

I am planning to use it for culling of the surface itself on draw side. Right now we don't cull surface quads at all, but we can cull them based on things outside the surface in the future.

The bool surfaceOccluded() method probably won't be used at the moment, but I included it just for completeness.

> Also, can you write a test for this function that does more than take in a rect and spit the same rect back out?

As we discussed, CCOcclusionTrackerTest.surfaceOcclusionInScreenSpace is meant to verify that this function works as intended. That said, if you can think of something more to test I'm very happy to!

> > Source/WebCore/platform/graphics/chromium/cc/CCOcclusionTracker.h:80
> > +    typedef void RenderSurfaceVoidType;
> > +
> > +    struct StackObject {
> > +        const RenderSurfaceVoidType* surface;
> 
> Along with the fact that a pair of types gets used consistently across all these functions, this piece of code says to me really says that your class should be templated.  Maybe I'm missing something, but I don't see a need for void pointer shenanigans.
> 
> Also, if the class were templated, you could just typedef CCOcclusionTracker(Impl) rather than adding boilerplate functions that thunk through.

As per offline discussion, going with templates and typedefs. It really cleaned up the .h so yay.
Comment 10 Dana Jansens 2012-02-21 19:58:01 PST
Created attachment 128120 [details]
Patch

For @enne review. Comments addressed!
Comment 11 Adrienne Walker 2012-02-21 20:38:06 PST
Comment on attachment 128120 [details]
Patch

Thanks for those changes! I don't think I have anything else to add.  :)
Comment 12 Dana Jansens 2012-02-21 21:06:42 PST
Comment on attachment 128120 [details]
Patch

Thanks enne! For @jamesr review then.
Comment 13 James Robinson 2012-02-21 23:05:15 PST
Comment on attachment 128120 [details]
Patch

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

Works for me! R=me with one style nit, feel free to address it when you address the other FIXME in that header.

> Source/WebCore/platform/graphics/chromium/cc/CCOcclusionTracker.h:94
> +    WTF_MAKE_NONCOPYABLE(CCOcclusionTrackerBase);

style nit: normally we put this right below the class declaration and above the first public:
Comment 14 WebKit Review Bot 2012-02-21 23:59:35 PST
Comment on attachment 128120 [details]
Patch

Clearing flags on attachment: 128120

Committed r108453: <http://trac.webkit.org/changeset/108453>
Comment 15 WebKit Review Bot 2012-02-21 23:59:42 PST
All reviewed patches have been landed.  Closing bug.
Comment 16 Yuta Kitamura 2012-02-22 01:37:02 PST
Hi,

Chromium's webkit_unit_tests started to fail since r108453:

http://build.chromium.org/p/chromium.webkit/builders/Webkit%20Linux%20%28dbg%29/builds/3657/steps/webkit_unit_tests/logs/stdio

[ RUN      ] CCOcclusionTrackerTest.surfaceOcclusionWithOverlappingSiblingSurfaces
ASSERTION FAILED: layer->targetRenderSurface() == m_stack.last().surface
third_party/WebKit/Source/WebCore/platform/graphics/chromium/cc/CCOcclusionTracker.cpp(217) : bool WebCore::CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::occluded(const LayerType*, const WebCore::IntRect&) const [with LayerType = WebCore::LayerChromium, RenderSurfaceType = WebCore::RenderSurfaceChromium]
1   0x1140ffc
2   0x546edc
3   0x791cc1
4   0x78e99e
5   0x7833a2
6   0x783bc6
7   0x7842bc
8   0x789093
9   0x792ebb
10  0x78f361
11  0x787bb0
12  0x7a31d5
13  0x41fc7d
14  0x7f63e50c2c4d __libc_start_main
15  0x41fb79
[56389:56389:0222/011121:15415134960585:ERROR:process_util_posix.cc(142)] Received signal 11
	base::debug::StackTrace::StackTrace() [0x1f69a3e]
	base::(anonymous namespace)::StackDumpSignalHandler() [0x1f1a9a5]
	0x7f63e50d7af0
	WebCore::CCOcclusionTrackerBase<>::occluded() [0x1141006]
	(anonymous namespace)::CCOcclusionTrackerTest_surfaceOcclusionWithOverlappingSiblingSurfaces_Test::TestBody() [0x546edc]
	testing::internal::HandleSehExceptionsInMethodIfSupported<>() [0x791cc1]
	testing::internal::HandleExceptionsInMethodIfSupported<>() [0x78e99e]
	testing::Test::Run() [0x7833a2]
	testing::TestInfo::Run() [0x783bc6]
	testing::TestCase::Run() [0x7842bc]
	testing::internal::UnitTestImpl::RunAllTests() [0x789093]
	testing::internal::HandleSehExceptionsInMethodIfSupported<>() [0x792ebb]
	testing::internal::HandleExceptionsInMethodIfSupported<>() [0x78f361]
	testing::UnitTest::Run() [0x787bb0]
	base::TestSuite::Run() [0x7a31d5]
	main [0x41fc7d]
	0x7f63e50c2c4d
	0x41fb79

Furthermore, one layout test started to fail and I'm suspecting this could be also due to r108453 (not 100% sure though):
http://test-results.appspot.com/dashboards/flakiness_dashboard.html#showExpectations=true&tests=fast%2Fcanvas%2Fwebgl%2Ftex-image-with-format-and-type.html

Could you take a look and fix them ASAP? I'm going to roll out the change unless I hear back from you.
Comment 17 Yuta Kitamura 2012-02-22 01:48:59 PST
I'm rolling out the change. Please fix the issue and land again.
Comment 18 Yuta Kitamura 2012-02-22 01:59:45 PST
Reverted r108453 for reason:

Broke Chromium's webkit_unit_tests.

Committed r108467: <http://trac.webkit.org/changeset/108467>
Comment 19 Yuta Kitamura 2012-02-22 04:37:09 PST
(In reply to comment #16)
> Furthermore, one layout test started to fail and I'm suspecting this could be also due to r108453 (not 100% sure though):

This wasn't true, because the test keeps failing even after the rollout.
Comment 20 Dana Jansens 2012-02-22 07:32:25 PST
Comment on attachment 128120 [details]
Patch

Ok, going to resubmit then.
Comment 21 W. James MacLean 2012-02-22 07:34:42 PST
Created attachment 128213 [details]
Patch for landing
Comment 22 WebKit Review Bot 2012-02-22 07:39:55 PST
Comment on attachment 128213 [details]
Patch for landing

Rejecting attachment 128213 [details] from commit-queue.

Failed to run "['/mnt/git/webkit-commit-queue/Tools/Scripts/webkit-patch', '--status-host=queues.webkit.org', '-..." exit_code: 1

ERROR: /mnt/git/webkit-commit-queue/Source/WebCore/ChangeLog neither lists a valid reviewer nor contains the string "Unreviewed" or "Rubber stamp" (case insensitive).

Full output: http://queues.webkit.org/results/11560504
Comment 23 W. James MacLean 2012-02-22 10:00:21 PST
Created attachment 128236 [details]
Patch for landing
Comment 24 WebKit Review Bot 2012-02-22 10:45:42 PST
Comment on attachment 128236 [details]
Patch for landing

Clearing flags on attachment: 128236

Committed r108521: <http://trac.webkit.org/changeset/108521>
Comment 25 WebKit Review Bot 2012-02-22 10:45:49 PST
All reviewed patches have been landed.  Closing bug.
Comment 26 Yuta Kitamura 2012-02-22 17:38:49 PST
(In reply to comment #20)
> (From update of attachment 128120 [details])
> Ok, going to resubmit then.

I'm sorry I wasn't clear, but I meant only layout test failure wasn't your fault. Your change still causes the following assertion failure.

ASSERTION FAILED: layer->targetRenderSurface() == m_stack.last().surface

Please investigate further as soon as possible. This error causes webkit_unit_tests to abort in the middle of the run, which is undesirable.
Comment 27 Yuta Kitamura 2012-02-22 18:21:58 PST
Um, you seem to fix the bug in r108587 (bug 79275).

Please leave some comments to show the linkage of bugs, and notify WebKit gardeners about build fixes from next time. Thanks.
Comment 28 Dana Jansens 2012-02-22 19:05:35 PST
Yup. Sorry! Enne knew about it at least, but I should have linked them.