OLD | NEW |
---|---|
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "cc/occlusion_tracker.h" | 5 #include "cc/occlusion_tracker.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "cc/layer.h" | 9 #include "cc/layer.h" |
10 #include "cc/layer_impl.h" | 10 #include "cc/layer_impl.h" |
11 #include "cc/math_util.h" | 11 #include "cc/math_util.h" |
12 #include "cc/overdraw_metrics.h" | 12 #include "cc/overdraw_metrics.h" |
13 #include "ui/gfx/quad_f.h" | 13 #include "ui/gfx/quad_f.h" |
14 #include "ui/gfx/rect_conversions.h" | 14 #include "ui/gfx/rect_conversions.h" |
15 | 15 |
16 using namespace std; | 16 using namespace std; |
17 | 17 |
18 namespace cc { | 18 namespace cc { |
19 | 19 |
20 template<typename LayerType, typename RenderSurfaceType> | 20 template<typename LayerType, typename RenderSurfaceType> |
21 OcclusionTrackerBase<LayerType, RenderSurfaceType>::OcclusionTrackerBase(gfx::Re ct rootTargetRect, bool recordMetricsForFrame) | 21 OcclusionTrackerBase<LayerType, RenderSurfaceType>::OcclusionTrackerBase(gfx::Re ct screenSpaceClipRect, bool recordMetricsForFrame) |
22 : m_rootTargetRect(rootTargetRect) | 22 : m_screenSpaceClipRect(screenSpaceClipRect) |
23 , m_overdrawMetrics(OverdrawMetrics::create(recordMetricsForFrame)) | 23 , m_overdrawMetrics(OverdrawMetrics::create(recordMetricsForFrame)) |
24 , m_occludingScreenSpaceRects(0) | 24 , m_occludingScreenSpaceRects(0) |
25 , m_nonOccludingScreenSpaceRects(0) | 25 , m_nonOccludingScreenSpaceRects(0) |
26 { | 26 { |
27 } | 27 } |
28 | 28 |
29 template<typename LayerType, typename RenderSurfaceType> | 29 template<typename LayerType, typename RenderSurfaceType> |
30 OcclusionTrackerBase<LayerType, RenderSurfaceType>::~OcclusionTrackerBase() | 30 OcclusionTrackerBase<LayerType, RenderSurfaceType>::~OcclusionTrackerBase() |
31 { | 31 { |
32 } | 32 } |
(...skipping 13 matching lines...) Expand all Loading... | |
46 void OcclusionTrackerBase<LayerType, RenderSurfaceType>::leaveLayer(const LayerI teratorPosition<LayerType>& layerIterator) | 46 void OcclusionTrackerBase<LayerType, RenderSurfaceType>::leaveLayer(const LayerI teratorPosition<LayerType>& layerIterator) |
47 { | 47 { |
48 LayerType* renderTarget = layerIterator.targetRenderSurfaceLayer; | 48 LayerType* renderTarget = layerIterator.targetRenderSurfaceLayer; |
49 | 49 |
50 if (layerIterator.representsItself) | 50 if (layerIterator.representsItself) |
51 markOccludedBehindLayer(layerIterator.currentLayer); | 51 markOccludedBehindLayer(layerIterator.currentLayer); |
52 else if (layerIterator.representsContributingRenderSurface) | 52 else if (layerIterator.representsContributingRenderSurface) |
53 leaveToRenderTarget(renderTarget); | 53 leaveToRenderTarget(renderTarget); |
54 } | 54 } |
55 | 55 |
56 template<typename LayerType, typename RenderSurfaceType> | 56 template<typename RenderSurfaceType> |
57 void OcclusionTrackerBase<LayerType, RenderSurfaceType>::enterRenderTarget(const LayerType* newTarget) | 57 static gfx::Rect screenSpaceClipRectInTargetSurface(const RenderSurfaceType* tar getSurface, gfx::Rect screenSpaceClipRect) |
enne (OOO)
2012/12/16 19:44:25
Do we not make this projection anywhere in LayerTr
danakj
2012/12/16 20:16:52
This looks a lot like clipRectFromAncestor for con
| |
58 { | 58 { |
59 if (!m_stack.empty() && m_stack.back().target == newTarget) | 59 gfx::Transform inverseScreenSpaceTransform; |
60 return; | 60 if (!targetSurface->screenSpaceTransform().GetInverse(&inverseScreenSpaceTra nsform)) |
61 return targetSurface->contentRect(); | |
61 | 62 |
62 const LayerType* oldTarget = m_stack.empty() ? 0 : m_stack.back().target; | 63 return gfx::ToEnclosingRect(MathUtil::projectClippedRect(inverseScreenSpaceT ransform, screenSpaceClipRect)); |
63 const RenderSurfaceType* oldAncestorThatMovesPixels = !oldTarget ? 0 : oldTa rget->renderSurface()->nearestAncestorThatMovesPixels(); | 64 } |
64 const RenderSurfaceType* newAncestorThatMovesPixels = newTarget->renderSurfa ce()->nearestAncestorThatMovesPixels(); | |
65 | 65 |
66 m_stack.push_back(StackObject(newTarget)); | 66 template<typename RenderSurfaceType> |
67 static Region transformSurfaceOpaqueRegion(const Region& region, bool haveClipRe ct, gfx::Rect clipRectInNewTarget, const gfx::Transform& transform) | |
68 { | |
69 if (region.IsEmpty()) | |
70 return Region(); | |
67 | 71 |
68 // We copy the screen occlusion into the new RenderSurfaceImpl subtree, but we never copy in the | 72 // Verify that rects within the |surface| will remain rects in its target su rface after applying |transform|. If this is true, then |
69 // target occlusion, since we are looking at a new RenderSurfaceImpl target. | 73 // apply |transform| to each rect within |region| in order to transform the entire Region. |
70 | 74 |
71 // If we are entering a subtree that is going to move pixels around, then th e occlusion we've computed | 75 bool clipped; |
72 // so far won't apply to the pixels we're drawing here in the same way. We d iscard the occlusion thus | 76 gfx::QuadF transformedBoundsQuad = MathUtil::mapQuad(transform, gfx::QuadF(r egion.bounds()), clipped); |
73 // far to be safe, and ensure we don't cull any pixels that are moved such t hat they become visible. | 77 // FIXME: Find a rect interior to each transformed quad. |
74 bool enteringSubtreeThatMovesPixels = newAncestorThatMovesPixels && newAnces torThatMovesPixels != oldAncestorThatMovesPixels; | 78 if (clipped || !transformedBoundsQuad.IsRectilinear()) |
79 return Region(); | |
75 | 80 |
76 bool copyScreenOcclusionForward = m_stack.size() > 1 && !enteringSubtreeThat MovesPixels; | 81 // TODO(danakj): If the Region is too complex, degrade gracefully here by sk ipping rects in it. |
enne (OOO)
2012/12/16 19:44:25
I think it'd be great if we had a Region-derived c
danakj
2012/12/16 20:16:52
I will make a bug for this too.
| |
77 if (copyScreenOcclusionForward) { | 82 Region transformedRegion; |
78 int lastIndex = m_stack.size() - 1; | 83 for (Region::Iterator rects(region); rects.has_rect(); rects.next()) { |
79 m_stack[lastIndex].occlusionInScreen = m_stack[lastIndex - 1].occlusionI nScreen; | 84 gfx::Rect transformedRect = gfx::ToEnclosedRect(MathUtil::mapQuad(transf orm, gfx::QuadF(rects.rect()), clipped).BoundingBox()); |
85 DCHECK(!clipped); // We only map if the transform preserves axis alignme nt. | |
86 if (haveClipRect) | |
87 transformedRect.Intersect(clipRectInNewTarget); | |
88 transformedRegion.Union(transformedRect); | |
80 } | 89 } |
90 return transformedRegion; | |
81 } | 91 } |
82 | 92 |
83 static inline bool layerOpacityKnown(const Layer* layer) { return !layer->drawOp acityIsAnimating(); } | 93 static inline bool layerOpacityKnown(const Layer* layer) { return !layer->drawOp acityIsAnimating(); } |
84 static inline bool layerOpacityKnown(const LayerImpl*) { return true; } | 94 static inline bool layerOpacityKnown(const LayerImpl*) { return true; } |
85 static inline bool layerTransformsToTargetKnown(const Layer* layer) { return !la yer->drawTransformIsAnimating(); } | 95 static inline bool layerTransformsToTargetKnown(const Layer* layer) { return !la yer->drawTransformIsAnimating(); } |
86 static inline bool layerTransformsToTargetKnown(const LayerImpl*) { return true; } | 96 static inline bool layerTransformsToTargetKnown(const LayerImpl*) { return true; } |
87 static inline bool layerTransformsToScreenKnown(const Layer* layer) { return !la yer->screenSpaceTransformIsAnimating(); } | |
88 static inline bool layerTransformsToScreenKnown(const LayerImpl*) { return true; } | |
89 | 97 |
90 static inline bool surfaceOpacityKnown(const RenderSurface* surface) { return !s urface->drawOpacityIsAnimating(); } | 98 static inline bool surfaceOpacityKnown(const RenderSurface* surface) { return !s urface->drawOpacityIsAnimating(); } |
91 static inline bool surfaceOpacityKnown(const RenderSurfaceImpl*) { return true; } | 99 static inline bool surfaceOpacityKnown(const RenderSurfaceImpl*) { return true; } |
92 static inline bool surfaceTransformsToTargetKnown(const RenderSurface* surface) { return !surface->targetSurfaceTransformsAreAnimating(); } | 100 static inline bool surfaceTransformsToTargetKnown(const RenderSurface* surface) { return !surface->targetSurfaceTransformsAreAnimating(); } |
93 static inline bool surfaceTransformsToTargetKnown(const RenderSurfaceImpl*) { re turn true; } | 101 static inline bool surfaceTransformsToTargetKnown(const RenderSurfaceImpl*) { re turn true; } |
94 static inline bool surfaceTransformsToScreenKnown(const RenderSurface* surface) { return !surface->screenSpaceTransformsAreAnimating(); } | 102 static inline bool surfaceTransformsToScreenKnown(const RenderSurface* surface) { return !surface->screenSpaceTransformsAreAnimating(); } |
95 static inline bool surfaceTransformsToScreenKnown(const RenderSurfaceImpl*) { re turn true; } | 103 static inline bool surfaceTransformsToScreenKnown(const RenderSurfaceImpl*) { re turn true; } |
96 | 104 |
97 static inline bool layerIsInUnsorted3dRenderingContext(const Layer* layer) { ret urn layer->parent() && layer->parent()->preserves3D(); } | 105 static inline bool layerIsInUnsorted3dRenderingContext(const Layer* layer) { ret urn layer->parent() && layer->parent()->preserves3D(); } |
98 static inline bool layerIsInUnsorted3dRenderingContext(const LayerImpl*) { retur n false; } | 106 static inline bool layerIsInUnsorted3dRenderingContext(const LayerImpl*) { retur n false; } |
99 | 107 |
100 template<typename LayerType, typename RenderSurfaceType> | 108 template<typename LayerType, typename RenderSurfaceType> |
109 void OcclusionTrackerBase<LayerType, RenderSurfaceType>::enterRenderTarget(const LayerType* newTarget) | |
110 { | |
111 if (!m_stack.empty() && m_stack.back().target == newTarget) | |
112 return; | |
113 | |
114 const LayerType* oldTarget = m_stack.empty() ? 0 : m_stack.back().target; | |
115 const RenderSurfaceType* oldAncestorThatMovesPixels = !oldTarget ? 0 : oldTa rget->renderSurface()->nearestAncestorThatMovesPixels(); | |
116 const RenderSurfaceType* newAncestorThatMovesPixels = newTarget->renderSurfa ce()->nearestAncestorThatMovesPixels(); | |
117 | |
118 m_stack.push_back(StackObject(newTarget)); | |
119 | |
120 // We copy the screen occlusion into the new RenderSurface subtree, but we n ever copy in the | |
121 // occlusion from inside the target, since we are looking at a new RenderSur face target. | |
122 | |
123 // If we are entering a subtree that is going to move pixels around, then th e occlusion we've computed | |
124 // so far won't apply to the pixels we're drawing here in the same way. We d iscard the occlusion thus | |
125 // far to be safe, and ensure we don't cull any pixels that are moved such t hat they become visible. | |
126 bool enteringSubtreeThatMovesPixels = newAncestorThatMovesPixels && newAnces torThatMovesPixels != oldAncestorThatMovesPixels; | |
127 | |
128 bool haveTransformFromScreenToNewTarget = false; | |
129 gfx::Transform inverseNewTargetScreenSpaceTransform; | |
130 if (surfaceTransformsToScreenKnown(newTarget->renderSurface())) | |
131 haveTransformFromScreenToNewTarget = newTarget->renderSurface()->screenS paceTransform().GetInverse(&inverseNewTargetScreenSpaceTransform); | |
132 | |
133 bool enteringRootTarget = newTarget->parent() == NULL; | |
134 | |
135 bool copyOutsideOcclusionForward = m_stack.size() > 1 && !enteringSubtreeTha tMovesPixels && haveTransformFromScreenToNewTarget && !enteringRootTarget; | |
136 if (!copyOutsideOcclusionForward) | |
137 return; | |
138 | |
139 int lastIndex = m_stack.size() - 1; | |
140 gfx::Transform oldTargetToNewTargetTransform(inverseNewTargetScreenSpaceTran sform, oldTarget->renderSurface()->screenSpaceTransform()); | |
141 m_stack[lastIndex].occlusionFromOutsideTarget = transformSurfaceOpaqueRegion <RenderSurfaceType>( | |
142 m_stack[lastIndex - 1].occlusionFromOutsideTarget, | |
143 false, | |
144 gfx::Rect(), | |
145 oldTargetToNewTargetTransform); | |
146 m_stack[lastIndex].occlusionFromOutsideTarget.Union(transformSurfaceOpaqueRe gion<RenderSurfaceType>( | |
147 m_stack[lastIndex - 1].occlusionFromInsideTarget, | |
148 false, | |
149 gfx::Rect(), | |
150 oldTargetToNewTargetTransform)); | |
151 } | |
152 | |
153 template<typename LayerType, typename RenderSurfaceType> | |
101 void OcclusionTrackerBase<LayerType, RenderSurfaceType>::finishedRenderTarget(co nst LayerType* finishedTarget) | 154 void OcclusionTrackerBase<LayerType, RenderSurfaceType>::finishedRenderTarget(co nst LayerType* finishedTarget) |
102 { | 155 { |
103 // Make sure we know about the target surface. | 156 // Make sure we know about the target surface. |
104 enterRenderTarget(finishedTarget); | 157 enterRenderTarget(finishedTarget); |
105 | 158 |
106 RenderSurfaceType* surface = finishedTarget->renderSurface(); | 159 RenderSurfaceType* surface = finishedTarget->renderSurface(); |
107 | 160 |
108 // If the occlusion within the surface can not be applied to things outside of the surface's subtree, then clear the occlusion here so it won't be used. | 161 // If the occlusion within the surface can not be applied to things outside of the surface's subtree, then clear the occlusion here so it won't be used. |
109 // TODO(senorblanco): Make this smarter for SkImageFilter case: once | 162 // TODO(senorblanco): Make this smarter for SkImageFilter case: once |
110 // SkImageFilters can report affectsOpacity(), call that. | 163 // SkImageFilters can report affectsOpacity(), call that. |
111 if (finishedTarget->maskLayer() || !surfaceOpacityKnown(surface) || surface- >drawOpacity() < 1 || finishedTarget->filters().hasFilterThatAffectsOpacity() || finishedTarget->filter()) { | 164 if (finishedTarget->maskLayer() || !surfaceOpacityKnown(surface) || surface- >drawOpacity() < 1 || finishedTarget->filters().hasFilterThatAffectsOpacity() || finishedTarget->filter()) { |
112 m_stack.back().occlusionInScreen.Clear(); | 165 m_stack.back().occlusionFromOutsideTarget.Clear(); |
113 m_stack.back().occlusionInTarget.Clear(); | 166 m_stack.back().occlusionFromInsideTarget.Clear(); |
114 } else { | 167 } else if (!surfaceTransformsToTargetKnown(surface)) { |
115 if (!surfaceTransformsToTargetKnown(surface)) | 168 m_stack.back().occlusionFromInsideTarget.Clear(); |
116 m_stack.back().occlusionInTarget.Clear(); | 169 m_stack.back().occlusionFromOutsideTarget.Clear(); |
117 if (!surfaceTransformsToScreenKnown(surface)) | |
118 m_stack.back().occlusionInScreen.Clear(); | |
119 } | 170 } |
120 } | 171 } |
121 | 172 |
122 template<typename RenderSurfaceType> | 173 template<typename LayerType> |
123 static inline Region transformSurfaceOpaqueRegion(const RenderSurfaceType* surfa ce, const Region& region, const gfx::Transform& transform) | 174 static void reduceOcclusionBelowSurface(LayerType* contributingLayer, const gfx: :Rect& surfaceRect, const gfx::Transform& surfaceTransform, LayerType* renderTar get, Region& occlusionFromInsideTarget) |
124 { | 175 { |
125 // Verify that rects within the |surface| will remain rects in its target su rface after applying |transform|. If this is true, then | 176 if (surfaceRect.IsEmpty()) |
126 // apply |transform| to each rect within |region| in order to transform the entire Region. | |
127 | |
128 bool clipped; | |
129 gfx::QuadF transformedBoundsQuad = MathUtil::mapQuad(transform, gfx::QuadF(r egion.bounds()), clipped); | |
130 // FIXME: Find a rect interior to each transformed quad. | |
131 if (clipped || !transformedBoundsQuad.IsRectilinear()) | |
132 return Region(); | |
133 | |
134 Region transformedRegion; | |
135 | |
136 for (Region::Iterator rects(region); rects.has_rect(); rects.next()) { | |
137 // We've already checked for clipping in the mapQuad call above, these c alls should not clip anything further. | |
138 gfx::Rect transformedRect = gfx::ToEnclosedRect(MathUtil::mapClippedRect (transform, gfx::RectF(rects.rect()))); | |
139 if (!surface->clipRect().IsEmpty()) | |
140 transformedRect.Intersect(surface->clipRect()); | |
141 transformedRegion.Union(transformedRect); | |
142 } | |
143 return transformedRegion; | |
144 } | |
145 | |
146 static inline void reduceOcclusion(const gfx::Rect& affectedArea, const gfx::Rec t& expandedPixel, Region& occlusion) | |
147 { | |
148 if (affectedArea.IsEmpty()) | |
149 return; | 177 return; |
150 | 178 |
151 Region affectedOcclusion = IntersectRegions(occlusion, affectedArea); | 179 gfx::Rect affectedAreaInTarget = gfx::ToEnclosingRect(MathUtil::mapClippedRe ct(surfaceTransform, gfx::RectF(surfaceRect))); |
180 if (contributingLayer->renderSurface()->isClipped()) | |
181 affectedAreaInTarget.Intersect(contributingLayer->renderSurface()->clipR ect()); | |
182 if (affectedAreaInTarget.IsEmpty()) | |
183 return; | |
184 | |
185 int outsetTop, outsetRight, outsetBottom, outsetLeft; | |
186 contributingLayer->backgroundFilters().getOutsets(outsetTop, outsetRight, ou tsetBottom, outsetLeft); | |
187 | |
188 // The filter can move pixels from outside of the clip, so allow affectedAre a to expand outside the clip. | |
189 affectedAreaInTarget.Inset(-outsetLeft, -outsetTop, -outsetRight, -outsetBot tom); | |
190 | |
191 gfx::Rect filterOutsetsInTarget(-outsetLeft, -outsetTop, outsetLeft + outset Right, outsetTop + outsetBottom); | |
192 | |
193 Region affectedOcclusion = IntersectRegions(occlusionFromInsideTarget, affec tedAreaInTarget); | |
152 Region::Iterator affectedOcclusionRects(affectedOcclusion); | 194 Region::Iterator affectedOcclusionRects(affectedOcclusion); |
153 | 195 |
154 occlusion.Subtract(affectedArea); | 196 occlusionFromInsideTarget.Subtract(affectedAreaInTarget); |
155 for (; affectedOcclusionRects.has_rect(); affectedOcclusionRects.next()) { | 197 for (; affectedOcclusionRects.has_rect(); affectedOcclusionRects.next()) { |
156 gfx::Rect occlusionRect = affectedOcclusionRects.rect(); | 198 gfx::Rect occlusionRect = affectedOcclusionRects.rect(); |
157 | 199 |
158 // Shrink the rect by expanding the non-opaque pixels outside the rect. | 200 // Shrink the rect by expanding the non-opaque pixels outside the rect. |
159 | 201 |
160 // The expandedPixel is the Rect for a single pixel after being | 202 // The left outset of the filters moves pixels on the right side of |
161 // expanded by filters on the layer. The original pixel would be | |
162 // Rect(0, 0, 1, 1), and the expanded pixel is the rect, relative | |
163 // to this original rect, that the original pixel can influence after | |
164 // being filtered. | |
165 // To convert the expandedPixel Rect back to filter outsets: | |
166 // x = -leftOutset | |
167 // width = leftOutset + rightOutset | |
168 // right = x + width = -leftOutset + leftOutset + rightOutset = rightOut set | |
169 | |
170 // The leftOutset of the filters moves pixels on the right side of | |
171 // the occlusionRect into it, shrinking its right edge. | 203 // the occlusionRect into it, shrinking its right edge. |
172 int shrinkLeft = occlusionRect.x() == affectedArea.x() ? 0 : expandedPix el.right(); | 204 int shrinkLeft = occlusionRect.x() == affectedAreaInTarget.x() ? 0 : out setRight; |
173 int shrinkTop = occlusionRect.y() == affectedArea.y() ? 0 : expandedPixe l.bottom(); | 205 int shrinkTop = occlusionRect.y() == affectedAreaInTarget.y() ? 0 : outs etBottom; |
174 int shrinkRight = occlusionRect.right() == affectedArea.right() ? 0 : -e xpandedPixel.x(); | 206 int shrinkRight = occlusionRect.right() == affectedAreaInTarget.right() ? 0 : outsetLeft; |
175 int shrinkBottom = occlusionRect.bottom() == affectedArea.bottom() ? 0 : -expandedPixel.y(); | 207 int shrinkBottom = occlusionRect.bottom() == affectedAreaInTarget.bottom () ? 0 : outsetTop; |
176 | 208 |
177 occlusionRect.Inset(shrinkLeft, shrinkTop, shrinkRight, shrinkBottom); | 209 occlusionRect.Inset(shrinkLeft, shrinkTop, shrinkRight, shrinkBottom); |
178 | 210 |
179 occlusion.Union(occlusionRect); | 211 occlusionFromInsideTarget.Union(occlusionRect); |
180 } | 212 } |
181 } | 213 } |
182 | 214 |
183 template<typename LayerType> | |
184 static void reduceOcclusionBelowSurface(LayerType* contributingLayer, const gfx: :Rect& surfaceRect, const gfx::Transform& surfaceTransform, LayerType* renderTar get, Region& occlusionInTarget, Region& occlusionInScreen) | |
185 { | |
186 if (surfaceRect.IsEmpty()) | |
187 return; | |
188 | |
189 gfx::Rect boundsInTarget = gfx::ToEnclosingRect(MathUtil::mapClippedRect(sur faceTransform, gfx::RectF(surfaceRect))); | |
190 if (!contributingLayer->renderSurface()->clipRect().IsEmpty()) | |
191 boundsInTarget.Intersect(contributingLayer->renderSurface()->clipRect()) ; | |
192 | |
193 int outsetTop, outsetRight, outsetBottom, outsetLeft; | |
194 contributingLayer->backgroundFilters().getOutsets(outsetTop, outsetRight, ou tsetBottom, outsetLeft); | |
195 | |
196 // The filter can move pixels from outside of the clip, so allow affectedAre a to expand outside the clip. | |
197 boundsInTarget.Inset(-outsetLeft, -outsetTop, -outsetRight, -outsetBottom); | |
198 | |
199 gfx::Rect boundsInScreen = gfx::ToEnclosingRect(MathUtil::mapClippedRect(ren derTarget->renderSurface()->screenSpaceTransform(), gfx::RectF(boundsInTarget))) ; | |
200 | |
201 gfx::Rect filterOutsetsInTarget(-outsetLeft, -outsetTop, outsetLeft + outset Right, outsetTop + outsetBottom); | |
202 gfx::Rect filterOutsetsInScreen = gfx::ToEnclosingRect(MathUtil::mapClippedR ect(renderTarget->renderSurface()->screenSpaceTransform(), gfx::RectF(filterOuts etsInTarget))); | |
203 | |
204 reduceOcclusion(boundsInTarget, filterOutsetsInTarget, occlusionInTarget); | |
205 reduceOcclusion(boundsInScreen, filterOutsetsInScreen, occlusionInScreen); | |
206 } | |
207 | |
208 template<typename LayerType, typename RenderSurfaceType> | 215 template<typename LayerType, typename RenderSurfaceType> |
209 void OcclusionTrackerBase<LayerType, RenderSurfaceType>::leaveToRenderTarget(con st LayerType* newTarget) | 216 void OcclusionTrackerBase<LayerType, RenderSurfaceType>::leaveToRenderTarget(con st LayerType* newTarget) |
210 { | 217 { |
211 int lastIndex = m_stack.size() - 1; | 218 int lastIndex = m_stack.size() - 1; |
212 bool surfaceWillBeAtTopAfterPop = m_stack.size() > 1 && m_stack[lastIndex - 1].target == newTarget; | 219 bool surfaceWillBeAtTopAfterPop = m_stack.size() > 1 && m_stack[lastIndex - 1].target == newTarget; |
213 | 220 |
214 // We merge the screen occlusion from the current RenderSurfaceImpl subtree out to its parent target RenderSurfaceImpl. | 221 // We merge the screen occlusion from the current RenderSurfaceImpl subtree out to its parent target RenderSurfaceImpl. |
215 // The target occlusion can be merged out as well but needs to be transforme d to the new target. | 222 // The target occlusion can be merged out as well but needs to be transforme d to the new target. |
216 | 223 |
217 const LayerType* oldTarget = m_stack[lastIndex].target; | 224 const LayerType* oldTarget = m_stack[lastIndex].target; |
218 const RenderSurfaceType* oldSurface = oldTarget->renderSurface(); | 225 const RenderSurfaceType* oldSurface = oldTarget->renderSurface(); |
219 Region oldTargetOcclusionInNewTarget = transformSurfaceOpaqueRegion<RenderSu rfaceType>(oldSurface, m_stack[lastIndex].occlusionInTarget, oldSurface->drawTra nsform()); | 226 |
227 Region oldOcclusionFromInsideTargetInNewTarget = transformSurfaceOpaqueRegio n<RenderSurfaceType>(m_stack[lastIndex].occlusionFromInsideTarget, oldSurface->i sClipped(), oldSurface->clipRect(), oldSurface->drawTransform()); | |
220 if (oldTarget->hasReplica() && !oldTarget->replicaHasMask()) | 228 if (oldTarget->hasReplica() && !oldTarget->replicaHasMask()) |
221 oldTargetOcclusionInNewTarget.Union(transformSurfaceOpaqueRegion<RenderS urfaceType>(oldSurface, m_stack[lastIndex].occlusionInTarget, oldSurface->replic aDrawTransform())); | 229 oldOcclusionFromInsideTargetInNewTarget.Union(transformSurfaceOpaqueRegi on<RenderSurfaceType>(m_stack[lastIndex].occlusionFromInsideTarget, oldSurface-> isClipped(), oldSurface->clipRect(), oldSurface->replicaDrawTransform())); |
230 | |
231 Region oldOcclusionFromOutsideTargetInNewTarget = transformSurfaceOpaqueRegi on<RenderSurfaceType>(m_stack[lastIndex].occlusionFromOutsideTarget, false, gfx: :Rect(), oldSurface->drawTransform()); | |
222 | 232 |
223 gfx::Rect unoccludedSurfaceRect; | 233 gfx::Rect unoccludedSurfaceRect; |
224 gfx::Rect unoccludedReplicaRect; | 234 gfx::Rect unoccludedReplicaRect; |
225 if (oldTarget->backgroundFilters().hasFilterThatMovesPixels()) { | 235 if (oldTarget->backgroundFilters().hasFilterThatMovesPixels()) { |
226 unoccludedSurfaceRect = unoccludedContributingSurfaceContentRect(oldTarg et, false, oldSurface->contentRect()); | 236 unoccludedSurfaceRect = unoccludedContributingSurfaceContentRect(oldTarg et, false, oldSurface->contentRect()); |
227 if (oldTarget->hasReplica()) | 237 if (oldTarget->hasReplica()) |
228 unoccludedReplicaRect = unoccludedContributingSurfaceContentRect(old Target, true, oldSurface->contentRect()); | 238 unoccludedReplicaRect = unoccludedContributingSurfaceContentRect(old Target, true, oldSurface->contentRect()); |
229 } | 239 } |
230 | 240 |
231 if (surfaceWillBeAtTopAfterPop) { | 241 if (surfaceWillBeAtTopAfterPop) { |
232 // Merge the top of the stack down. | 242 // Merge the top of the stack down. |
233 m_stack[lastIndex - 1].occlusionInScreen.Union(m_stack[lastIndex].occlus ionInScreen); | 243 m_stack[lastIndex - 1].occlusionFromInsideTarget.Union(oldOcclusionFromI nsideTargetInNewTarget); |
234 m_stack[lastIndex - 1].occlusionInTarget.Union(oldTargetOcclusionInNewTa rget); | 244 // TODO(danakj): Strictly this should subtract the inside target occlusi on before union. |
245 if (newTarget->parent()) | |
246 m_stack[lastIndex - 1].occlusionFromOutsideTarget.Union(oldOcclusion FromOutsideTargetInNewTarget); | |
235 m_stack.pop_back(); | 247 m_stack.pop_back(); |
236 } else { | 248 } else { |
237 // Replace the top of the stack with the new pushed surface. Copy the oc cluded screen region to the top. | 249 // Replace the top of the stack with the new pushed surface. |
238 m_stack.back().target = newTarget; | 250 m_stack.back().target = newTarget; |
239 m_stack.back().occlusionInTarget = oldTargetOcclusionInNewTarget; | 251 m_stack.back().occlusionFromInsideTarget = oldOcclusionFromInsideTargetI nNewTarget; |
252 if (newTarget->parent()) | |
253 m_stack.back().occlusionFromOutsideTarget = oldOcclusionFromOutsideT argetInNewTarget; | |
254 else | |
255 m_stack.back().occlusionFromOutsideTarget.Clear(); | |
240 } | 256 } |
241 | 257 |
242 if (oldTarget->backgroundFilters().hasFilterThatMovesPixels()) { | 258 if (!oldTarget->backgroundFilters().hasFilterThatMovesPixels()) |
243 reduceOcclusionBelowSurface(oldTarget, unoccludedSurfaceRect, oldSurface ->drawTransform(), newTarget, m_stack.back().occlusionInTarget, m_stack.back().o cclusionInScreen); | |
244 if (oldTarget->hasReplica()) | |
245 reduceOcclusionBelowSurface(oldTarget, unoccludedReplicaRect, oldSur face->replicaDrawTransform(), newTarget, m_stack.back().occlusionInTarget, m_sta ck.back().occlusionInScreen); | |
246 } | |
247 } | |
248 | |
249 // FIXME: Remove usePaintTracking when paint tracking is on for paint culling. | |
250 template<typename LayerType> | |
251 static inline void addOcclusionBehindLayer(Region& region, const LayerType* laye r, const gfx::Transform& transform, const Region& opaqueContents, const gfx::Rec t& clipRectInTarget, const gfx::Size& minimumTrackingSize, std::vector<gfx::Rect >* occludingScreenSpaceRects, std::vector<gfx::Rect>* nonOccludingScreenSpaceRec ts) | |
252 { | |
253 DCHECK(layer->visibleContentRect().Contains(opaqueContents.bounds())); | |
254 | |
255 bool clipped; | |
256 gfx::QuadF visibleTransformedQuad = MathUtil::mapQuad(transform, gfx::QuadF( layer->visibleContentRect()), clipped); | |
257 // FIXME: Find a rect interior to each transformed quad. | |
258 if (clipped || !visibleTransformedQuad.IsRectilinear()) | |
259 return; | 259 return; |
260 | 260 |
261 for (Region::Iterator opaqueContentRects(opaqueContents); opaqueContentRects .has_rect(); opaqueContentRects.next()) { | 261 reduceOcclusionBelowSurface(oldTarget, unoccludedSurfaceRect, oldSurface->dr awTransform(), newTarget, m_stack.back().occlusionFromInsideTarget); |
262 // We've already checked for clipping in the mapQuad call above, these c alls should not clip anything further. | 262 reduceOcclusionBelowSurface(oldTarget, unoccludedSurfaceRect, oldSurface->dr awTransform(), newTarget, m_stack.back().occlusionFromOutsideTarget); |
263 gfx::Rect transformedRect = gfx::ToEnclosedRect(MathUtil::mapClippedRect (transform, gfx::RectF(opaqueContentRects.rect()))); | |
264 transformedRect.Intersect(clipRectInTarget); | |
265 if (transformedRect.width() >= minimumTrackingSize.width() || transforme dRect.height() >= minimumTrackingSize.height()) { | |
266 if (occludingScreenSpaceRects) | |
267 occludingScreenSpaceRects->push_back(transformedRect); | |
268 region.Union(transformedRect); | |
269 } | |
270 } | |
271 | 263 |
272 if (nonOccludingScreenSpaceRects) { | 264 if (!oldTarget->hasReplica()) |
273 Region nonOpaqueContents = SubtractRegions(gfx::Rect(layer->contentBound s()), opaqueContents); | 265 return; |
274 for (Region::Iterator nonOpaqueContentRects(nonOpaqueContents); nonOpaqu eContentRects.has_rect(); nonOpaqueContentRects.next()) { | 266 reduceOcclusionBelowSurface(oldTarget, unoccludedReplicaRect, oldSurface->re plicaDrawTransform(), newTarget, m_stack.back().occlusionFromInsideTarget); |
275 // We've already checked for clipping in the mapQuad call above, the se calls should not clip anything further. | 267 reduceOcclusionBelowSurface(oldTarget, unoccludedReplicaRect, oldSurface->re plicaDrawTransform(), newTarget, m_stack.back().occlusionFromOutsideTarget); |
276 gfx::Rect transformedRect = gfx::ToEnclosedRect(MathUtil::mapClipped Rect(transform, gfx::RectF(nonOpaqueContentRects.rect()))); | |
277 transformedRect.Intersect(clipRectInTarget); | |
278 if (transformedRect.IsEmpty()) | |
279 continue; | |
280 nonOccludingScreenSpaceRects->push_back(transformedRect); | |
281 } | |
282 } | |
283 } | 268 } |
284 | 269 |
285 template<typename LayerType, typename RenderSurfaceType> | 270 template<typename LayerType, typename RenderSurfaceType> |
286 void OcclusionTrackerBase<LayerType, RenderSurfaceType>::markOccludedBehindLayer (const LayerType* layer) | 271 void OcclusionTrackerBase<LayerType, RenderSurfaceType>::markOccludedBehindLayer (const LayerType* layer) |
287 { | 272 { |
288 DCHECK(!m_stack.empty()); | 273 DCHECK(!m_stack.empty()); |
289 DCHECK(layer->renderTarget() == m_stack.back().target); | 274 DCHECK(layer->renderTarget() == m_stack.back().target); |
290 if (m_stack.empty()) | 275 if (m_stack.empty()) |
291 return; | 276 return; |
292 | 277 |
293 if (!layerOpacityKnown(layer) || layer->drawOpacity() < 1) | 278 if (!layerOpacityKnown(layer) || layer->drawOpacity() < 1) |
294 return; | 279 return; |
295 | 280 |
296 if (layerIsInUnsorted3dRenderingContext(layer)) | 281 if (layerIsInUnsorted3dRenderingContext(layer)) |
297 return; | 282 return; |
298 | 283 |
299 Region opaqueContents = layer->visibleContentOpaqueRegion(); | 284 Region opaqueContents = layer->visibleContentOpaqueRegion(); |
300 if (opaqueContents.IsEmpty()) | 285 if (opaqueContents.IsEmpty()) |
301 return; | 286 return; |
302 | 287 |
303 gfx::Rect clipRectInTarget = layerClipRectInTarget(layer); | 288 DCHECK(layer->visibleContentRect().Contains(opaqueContents.bounds())); |
304 if (layerTransformsToTargetKnown(layer)) | |
305 addOcclusionBehindLayer<LayerType>(m_stack.back().occlusionInTarget, lay er, layer->drawTransform(), opaqueContents, clipRectInTarget, m_minimumTrackingS ize, 0, 0); | |
306 | 289 |
307 // We must clip the occlusion within the layer's clipRectInTarget within scr een space as well. If the clip rect can't be moved to screen space and | 290 if (!layerTransformsToTargetKnown(layer)) |
308 // remain rectilinear, then we don't add any occlusion in screen space. | 291 return; |
309 | 292 |
310 if (layerTransformsToScreenKnown(layer)) { | 293 bool clipped; |
311 gfx::Transform targetToScreenTransform = m_stack.back().target->renderSu rface()->screenSpaceTransform(); | 294 gfx::QuadF visibleTransformedQuad = MathUtil::mapQuad(layer->drawTransform() , gfx::QuadF(opaqueContents.bounds()), clipped); |
312 bool clipped; | 295 // FIXME: Find a rect interior to each transformed quad. |
313 gfx::QuadF clipQuadInScreen = MathUtil::mapQuad(targetToScreenTransform, gfx::QuadF(clipRectInTarget), clipped); | 296 if (clipped || !visibleTransformedQuad.IsRectilinear()) |
314 // FIXME: Find a rect interior to the transformed clip quad. | 297 return; |
315 if (clipped || !clipQuadInScreen.IsRectilinear()) | 298 |
316 return; | 299 gfx::Rect clipRectInTarget = gfx::IntersectRects( |
317 gfx::Rect clipRectInScreen = gfx::IntersectRects(m_rootTargetRect, gfx:: ToEnclosedRect(clipQuadInScreen.BoundingBox())); | 300 layerClipRectInTarget(layer), |
318 addOcclusionBehindLayer<LayerType>(m_stack.back().occlusionInScreen, lay er, layer->screenSpaceTransform(), opaqueContents, clipRectInScreen, m_minimumTr ackingSize, m_occludingScreenSpaceRects, m_nonOccludingScreenSpaceRects); | 301 screenSpaceClipRectInTargetSurface(layer->renderTarget()->renderSurface( ), m_screenSpaceClipRect)); |
302 | |
303 for (Region::Iterator opaqueContentRects(opaqueContents); opaqueContentRects .has_rect(); opaqueContentRects.next()) { | |
304 gfx::Rect transformedRect = gfx::ToEnclosedRect(MathUtil::mapQuad(layer- >drawTransform(), gfx::QuadF(opaqueContentRects.rect()), clipped).BoundingBox()) ; | |
305 DCHECK(!clipped); // We only map if the transform preserves axis alignme nt. | |
306 transformedRect.Intersect(clipRectInTarget); | |
307 if (transformedRect.width() < m_minimumTrackingSize.width() && transform edRect.height() < m_minimumTrackingSize.height()) | |
308 continue; | |
309 m_stack.back().occlusionFromInsideTarget.Union(transformedRect); | |
310 | |
311 if (!m_occludingScreenSpaceRects) | |
312 continue; | |
313 | |
314 // Save the occluding area in screen space for debug visualization. | |
315 gfx::QuadF screenSpaceQuad = MathUtil::mapQuad(layer->renderTarget()->re nderSurface()->screenSpaceTransform(), gfx::QuadF(transformedRect), clipped); | |
316 // TODO(danakj): Store the quad in the debug info instead of the boundin g box. | |
317 gfx::Rect screenSpaceRect = gfx::ToEnclosedRect(screenSpaceQuad.Bounding Box()); | |
318 m_occludingScreenSpaceRects->push_back(screenSpaceRect); | |
319 } | 319 } |
320 } | |
321 | 320 |
322 static inline bool testContentRectOccluded(const gfx::Rect& contentRect, const g fx::Transform& contentSpaceTransform, const gfx::Rect& clipRectInTarget, const R egion& occlusion) | 321 if (!m_nonOccludingScreenSpaceRects) |
323 { | 322 return; |
324 gfx::RectF transformedRect = MathUtil::mapClippedRect(contentSpaceTransform, gfx::RectF(contentRect)); | 323 |
325 // Take the gfx::ToEnclosingRect, as we want to include partial pixels in th e test. | 324 Region nonOpaqueContents = SubtractRegions(gfx::Rect(layer->contentBounds()) , opaqueContents); |
326 gfx::Rect targetRect = gfx::IntersectRects(gfx::ToEnclosingRect(transformedR ect), clipRectInTarget); | 325 for (Region::Iterator nonOpaqueContentRects(nonOpaqueContents); nonOpaqueCon tentRects.has_rect(); nonOpaqueContentRects.next()) { |
327 return occlusion.Contains(targetRect); | 326 // We've already checked for clipping in the mapQuad call above, these c alls should not clip anything further. |
327 gfx::Rect transformedRect = gfx::ToEnclosedRect(MathUtil::mapClippedRect (layer->drawTransform(), gfx::RectF(nonOpaqueContentRects.rect()))); | |
328 transformedRect.Intersect(clipRectInTarget); | |
329 if (transformedRect.IsEmpty()) | |
330 continue; | |
331 | |
332 gfx::QuadF screenSpaceQuad = MathUtil::mapQuad(layer->renderTarget()->re nderSurface()->screenSpaceTransform(), gfx::QuadF(transformedRect), clipped); | |
333 // TODO(danakj): Store the quad in the debug info instead of the boundin g box. | |
334 gfx::Rect screenSpaceRect = gfx::ToEnclosedRect(screenSpaceQuad.Bounding Box()); | |
335 m_nonOccludingScreenSpaceRects->push_back(screenSpaceRect); | |
336 } | |
328 } | 337 } |
329 | 338 |
330 template<typename LayerType, typename RenderSurfaceType> | 339 template<typename LayerType, typename RenderSurfaceType> |
331 bool OcclusionTrackerBase<LayerType, RenderSurfaceType>::occluded(const LayerTyp e* renderTarget, const gfx::Rect& contentRect, const gfx::Transform& drawTransfo rm, bool implDrawTransformIsUnknown, const gfx::Rect& clippedRectInTarget, bool* hasOcclusionFromOutsideTargetSurface) const | 340 bool OcclusionTrackerBase<LayerType, RenderSurfaceType>::occluded(const LayerTyp e* renderTarget, const gfx::Rect& contentRect, const gfx::Transform& drawTransfo rm, bool implDrawTransformIsUnknown, const gfx::Rect& clippedRectInTarget, bool* hasOcclusionFromOutsideTargetSurface) const |
332 { | 341 { |
333 if (hasOcclusionFromOutsideTargetSurface) | |
334 *hasOcclusionFromOutsideTargetSurface = false; | |
335 | |
336 DCHECK(!m_stack.empty()); | 342 DCHECK(!m_stack.empty()); |
337 if (m_stack.empty()) | 343 if (m_stack.empty()) |
338 return false; | 344 return false; |
339 if (contentRect.IsEmpty()) | 345 if (contentRect.IsEmpty()) |
340 return true; | 346 return true; |
347 if (implDrawTransformIsUnknown) | |
348 return false; | |
341 | 349 |
350 // For tests with no render target. | |
351 if (!renderTarget) | |
352 return false; | |
353 | |
354 DCHECK(renderTarget->renderTarget() == renderTarget); | |
355 DCHECK(renderTarget->renderSurface()); | |
342 DCHECK(renderTarget == m_stack.back().target); | 356 DCHECK(renderTarget == m_stack.back().target); |
343 | 357 |
344 if (!implDrawTransformIsUnknown && testContentRectOccluded(contentRect, draw Transform, clippedRectInTarget, m_stack.back().occlusionInTarget)) | 358 gfx::Transform inverseDrawTransform; |
345 return true; | 359 if (!drawTransform.GetInverse(&inverseDrawTransform)) |
360 return false; | |
346 | 361 |
347 // renderTarget can be NULL in some tests. | 362 // Take the ToEnclosingRect at each step, as we want to contain any unocclud ed partial pixels in the resulting Rect. |
348 bool transformToScreenKnown = renderTarget && !implDrawTransformIsUnknown && layerTransformsToScreenKnown(renderTarget); | 363 gfx::Rect contentRectInTargetSurface = gfx::ToEnclosingRect(MathUtil::mapCli ppedRect(drawTransform, gfx::RectF(contentRect))); |
349 if (transformToScreenKnown && testContentRectOccluded(contentRect, renderTar get->renderSurface()->screenSpaceTransform() * drawTransform, m_rootTargetRect, m_stack.back().occlusionInScreen)) { | 364 contentRectInTargetSurface.Intersect(clippedRectInTarget); |
350 if (hasOcclusionFromOutsideTargetSurface) | 365 contentRectInTargetSurface.Intersect(screenSpaceClipRectInTargetSurface(rend erTarget->renderSurface(), m_screenSpaceClipRect)); |
351 *hasOcclusionFromOutsideTargetSurface = true; | 366 |
352 return true; | 367 Region unoccludedRegionInTargetSurface = contentRectInTargetSurface; |
368 unoccludedRegionInTargetSurface.Subtract(m_stack.back().occlusionFromInsideT arget); | |
369 gfx::RectF unoccludedRectInTargetSurfaceWithoutOutsideOcclusion = unoccluded RegionInTargetSurface.bounds(); | |
370 unoccludedRegionInTargetSurface.Subtract(m_stack.back().occlusionFromOutside Target); | |
371 | |
372 gfx::RectF unoccludedRectInTargetSurface = unoccludedRegionInTargetSurface.b ounds(); | |
373 | |
374 if (hasOcclusionFromOutsideTargetSurface) { | |
375 // Check if the unoccluded rect shank when applying outside occlusion. | |
376 *hasOcclusionFromOutsideTargetSurface = !gfx::SubtractRects(unoccludedRe ctInTargetSurfaceWithoutOutsideOcclusion, unoccludedRectInTargetSurface).IsEmpty (); | |
353 } | 377 } |
354 | 378 |
355 return false; | 379 return unoccludedRectInTargetSurface.IsEmpty(); |
356 } | |
357 | |
358 // Determines what portion of rect, if any, is unoccluded (not occluded by regio n). If | |
359 // the resulting unoccluded region is not rectangular, we return a rect containi ng it. | |
360 static inline gfx::Rect rectSubtractRegion(const gfx::Rect& rect, const Region& region) | |
361 { | |
362 if (region.IsEmpty()) | |
363 return rect; | |
364 | |
365 Region rectRegion(rect); | |
366 rectRegion.Subtract(region); | |
367 return rectRegion.bounds(); | |
368 } | |
369 | |
370 static inline gfx::Rect computeUnoccludedContentRect(const gfx::Rect& contentRec t, const gfx::Transform& contentSpaceTransform, const gfx::Rect& clipRectInTarge t, const Region& occlusion) | |
371 { | |
372 if (!contentSpaceTransform.IsInvertible()) | |
373 return contentRect; | |
374 | |
375 // Take the ToEnclosingRect at each step, as we want to contain any unocclud ed partial pixels in the resulting Rect. | |
376 gfx::RectF transformedRect = MathUtil::mapClippedRect(contentSpaceTransform, gfx::RectF(contentRect)); | |
377 gfx::Rect shrunkRect = rectSubtractRegion(gfx::IntersectRects(gfx::ToEnclosi ngRect(transformedRect), clipRectInTarget), occlusion); | |
378 gfx::Rect unoccludedRect = gfx::ToEnclosingRect(MathUtil::projectClippedRect (MathUtil::inverse(contentSpaceTransform), gfx::RectF(shrunkRect))); | |
379 // The rect back in content space is a bounding box and may extend outside o f the original contentRect, so clamp it to the contentRectBounds. | |
380 return gfx::IntersectRects(unoccludedRect, contentRect); | |
381 } | 380 } |
382 | 381 |
383 template<typename LayerType, typename RenderSurfaceType> | 382 template<typename LayerType, typename RenderSurfaceType> |
384 gfx::Rect OcclusionTrackerBase<LayerType, RenderSurfaceType>::unoccludedContentR ect(const LayerType* renderTarget, const gfx::Rect& contentRect, const gfx::Tran sform& drawTransform, bool implDrawTransformIsUnknown, const gfx::Rect& clippedR ectInTarget, bool* hasOcclusionFromOutsideTargetSurface) const | 383 gfx::Rect OcclusionTrackerBase<LayerType, RenderSurfaceType>::unoccludedContentR ect(const LayerType* renderTarget, const gfx::Rect& contentRect, const gfx::Tran sform& drawTransform, bool implDrawTransformIsUnknown, const gfx::Rect& clippedR ectInTarget, bool* hasOcclusionFromOutsideTargetSurface) const |
385 { | 384 { |
386 DCHECK(!m_stack.empty()); | 385 DCHECK(!m_stack.empty()); |
387 if (m_stack.empty()) | 386 if (m_stack.empty()) |
388 return contentRect; | 387 return contentRect; |
389 if (contentRect.IsEmpty()) | 388 if (contentRect.IsEmpty()) |
390 return contentRect; | 389 return contentRect; |
390 if (implDrawTransformIsUnknown) | |
391 return contentRect; | |
392 | |
393 // For tests with no render target. | |
394 if (!renderTarget) | |
395 return contentRect; | |
391 | 396 |
392 DCHECK(renderTarget->renderTarget() == renderTarget); | 397 DCHECK(renderTarget->renderTarget() == renderTarget); |
393 DCHECK(renderTarget->renderSurface()); | 398 DCHECK(renderTarget->renderSurface()); |
394 DCHECK(renderTarget == m_stack.back().target); | 399 DCHECK(renderTarget == m_stack.back().target); |
395 | 400 |
396 // We want to return a rect that contains all the visible parts of |contentR ect| in both screen space and in the target surface. | 401 gfx::Transform inverseDrawTransform; |
397 // So we find the visible parts of |contentRect| in each space, and take the intersection. | 402 if (!drawTransform.GetInverse(&inverseDrawTransform)) |
403 return contentRect; | |
398 | 404 |
399 gfx::Rect unoccludedInScreen = contentRect; | 405 // Take the ToEnclosingRect at each step, as we want to contain any unocclud ed partial pixels in the resulting Rect. |
400 if (layerTransformsToScreenKnown(renderTarget) && !implDrawTransformIsUnknow n) | 406 gfx::Rect contentRectInTargetSurface = gfx::ToEnclosingRect(MathUtil::mapCli ppedRect(drawTransform, gfx::RectF(contentRect))); |
401 unoccludedInScreen = computeUnoccludedContentRect(contentRect, renderTar get->renderSurface()->screenSpaceTransform() * drawTransform, m_rootTargetRect, m_stack.back().occlusionInScreen); | 407 contentRectInTargetSurface.Intersect(clippedRectInTarget); |
408 contentRectInTargetSurface.Intersect(screenSpaceClipRectInTargetSurface(rend erTarget->renderSurface(), m_screenSpaceClipRect)); | |
402 | 409 |
403 gfx::Rect unoccludedInTarget = contentRect; | 410 Region unoccludedRegionInTargetSurface = contentRectInTargetSurface; |
404 if (!implDrawTransformIsUnknown) | 411 unoccludedRegionInTargetSurface.Subtract(m_stack.back().occlusionFromInsideT arget); |
405 unoccludedInTarget = computeUnoccludedContentRect(contentRect, drawTrans form, clippedRectInTarget, m_stack.back().occlusionInTarget); | 412 gfx::RectF unoccludedRectInTargetSurfaceWithoutOutsideOcclusion = unoccluded RegionInTargetSurface.bounds(); |
413 unoccludedRegionInTargetSurface.Subtract(m_stack.back().occlusionFromOutside Target); | |
406 | 414 |
407 if (hasOcclusionFromOutsideTargetSurface) | 415 gfx::RectF unoccludedRectInTargetSurface = unoccludedRegionInTargetSurface.b ounds(); |
408 *hasOcclusionFromOutsideTargetSurface = (gfx::IntersectRects(unoccludedI nScreen, unoccludedInTarget) != unoccludedInTarget); | 416 gfx::Rect unoccludedRect = gfx::ToEnclosingRect(MathUtil::projectClippedRect (inverseDrawTransform, unoccludedRectInTargetSurface)); |
417 unoccludedRect.Intersect(contentRect); | |
409 | 418 |
410 return gfx::IntersectRects(unoccludedInScreen, unoccludedInTarget); | 419 if (hasOcclusionFromOutsideTargetSurface) { |
420 // Check if the unoccluded rect shank when applying outside occlusion. | |
jamesr
2012/12/16 00:27:54
typo shank -> shrank
danakj
2012/12/16 21:30:03
Done.
| |
421 *hasOcclusionFromOutsideTargetSurface = !gfx::SubtractRects(unoccludedRe ctInTargetSurfaceWithoutOutsideOcclusion, unoccludedRectInTargetSurface).IsEmpty (); | |
422 } | |
423 | |
424 return unoccludedRect; | |
411 } | 425 } |
412 | 426 |
413 template<typename LayerType, typename RenderSurfaceType> | 427 template<typename LayerType, typename RenderSurfaceType> |
414 gfx::Rect OcclusionTrackerBase<LayerType, RenderSurfaceType>::unoccludedContribu tingSurfaceContentRect(const LayerType* layer, bool forReplica, const gfx::Rect& contentRect, bool* hasOcclusionFromOutsideTargetSurface) const | 428 gfx::Rect OcclusionTrackerBase<LayerType, RenderSurfaceType>::unoccludedContribu tingSurfaceContentRect(const LayerType* layer, bool forReplica, const gfx::Rect& contentRect, bool* hasOcclusionFromOutsideTargetSurface) const |
415 { | 429 { |
416 DCHECK(!m_stack.empty()); | 430 DCHECK(!m_stack.empty()); |
417 // The layer is a contributing renderTarget so it should have a surface. | 431 // The layer is a contributing renderTarget so it should have a surface. |
418 DCHECK(layer->renderSurface()); | 432 DCHECK(layer->renderSurface()); |
419 // The layer is a contributing renderTarget so its target should be itself. | 433 // The layer is a contributing renderTarget so its target should be itself. |
420 DCHECK(layer->renderTarget() == layer); | 434 DCHECK(layer->renderTarget() == layer); |
421 // The layer should not be the root, else what is is contributing to? | 435 // The layer should not be the root, else what is is contributing to? |
422 DCHECK(layer->parent()); | 436 DCHECK(layer->parent()); |
423 // This should be called while the layer is still considered the current tar get in the occlusion tracker. | 437 // This should be called while the layer is still considered the current tar get in the occlusion tracker. |
424 DCHECK(layer == m_stack.back().target); | 438 DCHECK(layer == m_stack.back().target); |
425 | 439 |
426 if (contentRect.IsEmpty()) | 440 if (contentRect.IsEmpty()) |
427 return contentRect; | 441 return contentRect; |
428 | 442 |
429 RenderSurfaceType* surface = layer->renderSurface(); | 443 const RenderSurfaceType* surface = layer->renderSurface(); |
444 const LayerType* contributingSurfaceRenderTarget = layer->parent()->renderTa rget(); | |
430 | 445 |
431 gfx::Rect surfaceClipRect = surface->clipRect(); | 446 if (!surfaceTransformsToTargetKnown(surface)) |
432 if (surfaceClipRect.IsEmpty()) { | 447 return contentRect; |
433 const LayerType* contributingSurfaceRenderTarget = layer->parent()->rend erTarget(); | 448 |
434 surfaceClipRect = gfx::IntersectRects(contributingSurfaceRenderTarget->r enderSurface()->contentRect(), gfx::ToEnclosingRect(surface->drawableContentRect ())); | 449 gfx::Transform drawTransform = forReplica ? surface->replicaDrawTransform() : surface->drawTransform(); |
450 gfx::Transform inverseDrawTransform; | |
451 if (!drawTransform.GetInverse(&inverseDrawTransform)) | |
452 return contentRect; | |
453 | |
454 // Take the ToEnclosingRect at each step, as we want to contain any unocclud ed partial pixels in the resulting Rect. | |
455 gfx::Rect contentRectInTargetSurface = gfx::ToEnclosingRect(MathUtil::mapCli ppedRect(drawTransform, gfx::RectF(contentRect))); | |
456 if (surface->isClipped()) { | |
457 contentRectInTargetSurface.Intersect(surface->clipRect()); | |
458 } else { | |
459 contentRectInTargetSurface.Intersect(contributingSurfaceRenderTarget->re nderSurface()->contentRect()); | |
460 contentRectInTargetSurface.Intersect(gfx::ToEnclosingRect(surface->drawa bleContentRect())); | |
435 } | 461 } |
462 contentRectInTargetSurface.Intersect(screenSpaceClipRectInTargetSurface(cont ributingSurfaceRenderTarget->renderSurface(), m_screenSpaceClipRect)); | |
463 | |
464 gfx::RectF unoccludedRectInTargetSurface; | |
436 | 465 |
437 // A contributing surface doesn't get occluded by things inside its own surf ace, so only things outside the surface can occlude it. That occlusion is | 466 // A contributing surface doesn't get occluded by things inside its own surf ace, so only things outside the surface can occlude it. That occlusion is |
438 // found just below the top of the stack (if it exists). | 467 // found just below the top of the stack (if it exists). |
439 bool hasOcclusion = m_stack.size() > 1; | 468 bool hasOcclusion = m_stack.size() > 1; |
469 if (hasOcclusion) { | |
470 const StackObject& secondLast = m_stack[m_stack.size() - 2]; | |
471 Region unoccludedRegionInTargetSurface = contentRectInTargetSurface; | |
472 unoccludedRegionInTargetSurface.Subtract(secondLast.occlusionFromInsideT arget); | |
473 gfx::RectF unoccludedRectInTargetSurfaceWithoutOutsideOcclusion = unoccl udedRegionInTargetSurface.bounds(); | |
474 unoccludedRegionInTargetSurface.Subtract(secondLast.occlusionFromOutside Target); | |
440 | 475 |
441 const gfx::Transform& transformToScreen = forReplica ? surface->replicaScree nSpaceTransform() : surface->screenSpaceTransform(); | 476 unoccludedRectInTargetSurface = unoccludedRegionInTargetSurface.bounds() ; |
442 const gfx::Transform& transformToTarget = forReplica ? surface->replicaDrawT ransform() : surface->drawTransform(); | |
443 | 477 |
444 gfx::Rect unoccludedInScreen = contentRect; | 478 if (hasOcclusionFromOutsideTargetSurface) { |
445 if (surfaceTransformsToScreenKnown(surface)) { | 479 // Check if the unoccluded rect shank when applying outside occlusio n. |
jamesr
2012/12/16 00:27:54
same typo
danakj
2012/12/16 21:30:03
Done.
| |
446 if (hasOcclusion) { | 480 *hasOcclusionFromOutsideTargetSurface = !gfx::SubtractRects(unocclud edRectInTargetSurfaceWithoutOutsideOcclusion, unoccludedRectInTargetSurface).IsE mpty(); |
447 const StackObject& secondLast = m_stack[m_stack.size() - 2]; | 481 } |
448 unoccludedInScreen = computeUnoccludedContentRect(contentRect, trans formToScreen, m_rootTargetRect, secondLast.occlusionInScreen); | 482 } else { |
449 } else | 483 unoccludedRectInTargetSurface = contentRectInTargetSurface; |
450 unoccludedInScreen = computeUnoccludedContentRect(contentRect, trans formToScreen, m_rootTargetRect, Region()); | 484 if (hasOcclusionFromOutsideTargetSurface) |
485 *hasOcclusionFromOutsideTargetSurface = false; | |
451 } | 486 } |
452 | 487 |
453 gfx::Rect unoccludedInTarget = contentRect; | 488 gfx::Rect unoccludedRect = gfx::ToEnclosingRect(MathUtil::projectClippedRect (inverseDrawTransform, unoccludedRectInTargetSurface)); |
454 if (surfaceTransformsToTargetKnown(surface)) { | 489 unoccludedRect.Intersect(contentRect); |
455 if (hasOcclusion) { | |
456 const StackObject& secondLast = m_stack[m_stack.size() - 2]; | |
457 unoccludedInTarget = computeUnoccludedContentRect(contentRect, trans formToTarget, surfaceClipRect, secondLast.occlusionInTarget); | |
458 } else | |
459 unoccludedInTarget = computeUnoccludedContentRect(contentRect, trans formToTarget, surfaceClipRect, Region()); | |
460 } | |
461 | 490 |
462 if (hasOcclusionFromOutsideTargetSurface) | 491 return unoccludedRect; |
463 *hasOcclusionFromOutsideTargetSurface = (gfx::IntersectRects(unoccludedI nScreen, unoccludedInTarget) != unoccludedInTarget); | |
464 | |
465 return gfx::IntersectRects(unoccludedInScreen, unoccludedInTarget); | |
466 } | 492 } |
467 | 493 |
468 template<typename LayerType, typename RenderSurfaceType> | 494 template<typename LayerType, typename RenderSurfaceType> |
469 gfx::Rect OcclusionTrackerBase<LayerType, RenderSurfaceType>::layerClipRectInTar get(const LayerType* layer) const | 495 gfx::Rect OcclusionTrackerBase<LayerType, RenderSurfaceType>::layerClipRectInTar get(const LayerType* layer) const |
470 { | 496 { |
471 // FIXME: we could remove this helper function, but unit tests currently ove rride this | 497 // TODO(danakj): Can we remove this use of drawableContentRect and just use the clipRect() and target surface contentRect? |
472 // function, and they need to be verified/adjusted before this can be removed. | |
473 return layer->drawableContentRect(); | 498 return layer->drawableContentRect(); |
474 } | 499 } |
475 | 500 |
476 // Instantiate (and export) templates here for the linker. | 501 // Instantiate (and export) templates here for the linker. |
477 template class OcclusionTrackerBase<Layer, RenderSurface>; | 502 template class OcclusionTrackerBase<Layer, RenderSurface>; |
478 template class OcclusionTrackerBase<LayerImpl, RenderSurfaceImpl>; | 503 template class OcclusionTrackerBase<LayerImpl, RenderSurfaceImpl>; |
479 | 504 |
480 } // namespace cc | 505 } // namespace cc |
OLD | NEW |