Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(742)

Side by Side Diff: ui/cc/cc/CCLayerSorter.cpp

Issue 10701016: Initial import attempt, just to play with. Many things disabled/removed (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ui/cc/cc/CCLayerSorter.h ('k') | ui/cc/cc/CCLayerTilingData.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2011 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND AN Y
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR AN Y
17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND O N
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25 #include "config.h"
26
27 #include "cc/CCLayerSorter.h"
28
29 #include "cc/CCMathUtil.h"
30 #include "cc/CCRenderSurface.h"
31 #include <limits.h>
32 #include <public/WebTransformationMatrix.h>
33 #include <wtf/Deque.h>
34
35 using namespace std;
36 using WebKit::WebTransformationMatrix;
37
38 #define LOG_CHANNEL_PREFIX Log
39 #define SHOW_DEBUG_LOG 0
40
41 #if !defined( NDEBUG )
42 #if SHOW_DEBUG_LOG
43 static WTFLogChannel LogCCLayerSorter = { 0x00000000, "", WTFLogChannelOn };
44 #else
45 static WTFLogChannel LogCCLayerSorter = { 0x00000000, "", WTFLogChannelOff };
46 #endif
47 #endif
48
49 namespace WebCore {
50
51 inline static float perpProduct(const FloatSize& u, const FloatSize& v)
52 {
53 return u.width() * v.height() - u.height() * v.width();
54 }
55
56 // Tests if two edges defined by their endpoints (a,b) and (c,d) intersect. Retu rns true and the
57 // point of intersection if they do and false otherwise.
58 static bool edgeEdgeTest(const FloatPoint& a, const FloatPoint& b, const FloatPo int& c, const FloatPoint& d, FloatPoint& r)
59 {
60 FloatSize u = b - a;
61 FloatSize v = d - c;
62 FloatSize w = a - c;
63
64 float denom = perpProduct(u, v);
65
66 // If denom == 0 then the edges are parallel. While they could be overlappin g
67 // we don't bother to check here as the we'll find their intersections from the
68 // corner to quad tests.
69 if (!denom)
70 return false;
71
72 float s = perpProduct(v, w) / denom;
73 if (s < 0 || s > 1)
74 return false;
75
76 float t = perpProduct(u, w) / denom;
77 if (t < 0 || t > 1)
78 return false;
79
80 u.scale(s);
81 r = a + u;
82 return true;
83 }
84
85 // Checks whether layer "a" draws on top of layer "b". The weight value returned is an indication of
86 // the maximum z-depth difference between the layers or zero if the layers are f ound to be intesecting
87 // (some features are in front and some are behind).
88 CCLayerSorter::ABCompareResult CCLayerSorter::checkOverlap(LayerShape* a, LayerS hape* b, float zThreshold, float& weight)
89 {
90 weight = 0;
91
92 // Early out if the projected bounds don't overlap.
93 if (!a->projectedBounds.intersects(b->projectedBounds))
94 return None;
95
96 FloatPoint aPoints[4] = {a->projectedQuad.p1(), a->projectedQuad.p2(), a->pr ojectedQuad.p3(), a->projectedQuad.p4() };
97 FloatPoint bPoints[4] = {b->projectedQuad.p1(), b->projectedQuad.p2(), b->pr ojectedQuad.p3(), b->projectedQuad.p4() };
98
99 // Make a list of points that inside both layer quad projections.
100 Vector<FloatPoint> overlapPoints;
101
102 // Check all four corners of one layer against the other layer's quad.
103 for (int i = 0; i < 4; ++i) {
104 if (a->projectedQuad.containsPoint(bPoints[i]))
105 overlapPoints.append(bPoints[i]);
106 if (b->projectedQuad.containsPoint(aPoints[i]))
107 overlapPoints.append(aPoints[i]);
108 }
109
110 // Check all the edges of one layer for intersection with the other layer's edges.
111 FloatPoint r;
112 for (int ea = 0; ea < 4; ++ea)
113 for (int eb = 0; eb < 4; ++eb)
114 if (edgeEdgeTest(aPoints[ea], aPoints[(ea + 1) % 4],
115 bPoints[eb], bPoints[(eb + 1) % 4],
116 r))
117 overlapPoints.append(r);
118
119 if (!overlapPoints.size())
120 return None;
121
122 // Check the corresponding layer depth value for all overlap points to deter mine
123 // which layer is in front.
124 float maxPositive = 0;
125 float maxNegative = 0;
126 for (unsigned o = 0; o < overlapPoints.size(); o++) {
127 float za = a->layerZFromProjectedPoint(overlapPoints[o]);
128 float zb = b->layerZFromProjectedPoint(overlapPoints[o]);
129
130 float diff = za - zb;
131 if (diff > maxPositive)
132 maxPositive = diff;
133 if (diff < maxNegative)
134 maxNegative = diff;
135 }
136
137 float maxDiff = (fabsf(maxPositive) > fabsf(maxNegative) ? maxPositive : max Negative);
138
139 // If the results are inconsistent (and the z difference substantial to rule out
140 // numerical errors) then the layers are intersecting. We will still return an
141 // order based on the maximum depth difference but with an edge weight of ze ro
142 // these layers will get priority if a graph cycle is present and needs to b e broken.
143 if (maxPositive > zThreshold && maxNegative < -zThreshold)
144 weight = 0;
145 else
146 weight = fabsf(maxDiff);
147
148 // Maintain relative order if the layers have the same depth at all intersec tion points.
149 if (maxDiff <= 0)
150 return ABeforeB;
151
152 return BBeforeA;
153 }
154
155 CCLayerSorter::LayerShape::LayerShape(float width, float height, const WebTransf ormationMatrix& drawTransform)
156 {
157 FloatQuad layerQuad(FloatPoint(-width * 0.5, height * 0.5),
158 FloatPoint(width * 0.5, height * 0.5),
159 FloatPoint(width * 0.5, -height * 0.5),
160 FloatPoint(-width * 0.5, -height * 0.5));
161
162 // Compute the projection of the layer quad onto the z = 0 plane.
163
164 FloatPoint clippedQuad[8];
165 int numVerticesInClippedQuad;
166 CCMathUtil::mapClippedQuad(drawTransform, layerQuad, clippedQuad, numVertice sInClippedQuad);
167
168 if (numVerticesInClippedQuad < 3) {
169 projectedBounds = FloatRect();
170 return;
171 }
172
173 projectedBounds = CCMathUtil::computeEnclosingRectOfVertices(clippedQuad, nu mVerticesInClippedQuad);
174
175 // NOTE: it will require very significant refactoring and overhead to deal w ith
176 // generalized polygons or multiple quads per layer here. For the sake of la yer
177 // sorting it is equally correct to take a subsection of the polygon that ca n be made
178 // into a quad. This will only be incorrect in the case of intersecting laye rs, which
179 // are not supported yet anyway.
180 projectedQuad.setP1(clippedQuad[0]);
181 projectedQuad.setP2(clippedQuad[1]);
182 projectedQuad.setP3(clippedQuad[2]);
183 if (numVerticesInClippedQuad >= 4)
184 projectedQuad.setP4(clippedQuad[3]);
185 else
186 projectedQuad.setP4(clippedQuad[2]); // this will be a degenerate quad t hat is actually a triangle.
187
188 // Compute the normal of the layer's plane.
189 FloatPoint3D c1 = drawTransform.mapPoint(FloatPoint3D(0, 0, 0));
190 FloatPoint3D c2 = drawTransform.mapPoint(FloatPoint3D(0, 1, 0));
191 FloatPoint3D c3 = drawTransform.mapPoint(FloatPoint3D(1, 0, 0));
192 FloatPoint3D c12 = c2 - c1;
193 FloatPoint3D c13 = c3 - c1;
194 layerNormal = c13.cross(c12);
195
196 transformOrigin = c1;
197 }
198
199 // Returns the Z coordinate of a point on the layer that projects
200 // to point p which lies on the z = 0 plane. It does it by computing the
201 // intersection of a line starting from p along the Z axis and the plane
202 // of the layer.
203 float CCLayerSorter::LayerShape::layerZFromProjectedPoint(const FloatPoint& p) c onst
204 {
205 const FloatPoint3D zAxis(0, 0, 1);
206 FloatPoint3D w = FloatPoint3D(p) - transformOrigin;
207
208 float d = layerNormal.dot(zAxis);
209 float n = -layerNormal.dot(w);
210
211 // Check if layer is parallel to the z = 0 axis which will make it
212 // invisible and hence returning zero is fine.
213 if (!d)
214 return 0;
215
216 // The intersection point would be given by:
217 // p + (n / d) * u but since we are only interested in the
218 // z coordinate and p's z coord is zero, all we need is the value of n/d.
219 return n / d;
220 }
221
222 void CCLayerSorter::createGraphNodes(LayerList::iterator first, LayerList::itera tor last)
223 {
224 #if !defined( NDEBUG )
225 LOG(CCLayerSorter, "Creating graph nodes:\n");
226 #endif
227 float minZ = FLT_MAX;
228 float maxZ = -FLT_MAX;
229 for (LayerList::const_iterator it = first; it < last; it++) {
230 m_nodes.append(GraphNode(*it));
231 GraphNode& node = m_nodes.at(m_nodes.size() - 1);
232 CCRenderSurface* renderSurface = node.layer->renderSurface();
233 if (!node.layer->drawsContent() && !renderSurface)
234 continue;
235
236 #if !defined( NDEBUG )
237 LOG(CCLayerSorter, "Layer %d (%d x %d)\n", node.layer->id(), node.layer- >bounds().width(), node.layer->bounds().height());
238 #endif
239
240 WebTransformationMatrix drawTransform;
241 float layerWidth, layerHeight;
242 if (renderSurface) {
243 drawTransform = renderSurface->drawTransform();
244 layerWidth = renderSurface->contentRect().width();
245 layerHeight = renderSurface->contentRect().height();
246 } else {
247 drawTransform = node.layer->drawTransform();
248 layerWidth = node.layer->bounds().width();
249 layerHeight = node.layer->bounds().height();
250 }
251
252 node.shape = LayerShape(layerWidth, layerHeight, drawTransform);
253
254 maxZ = max(maxZ, node.shape.transformOrigin.z());
255 minZ = min(minZ, node.shape.transformOrigin.z());
256 }
257
258 m_zRange = fabsf(maxZ - minZ);
259 }
260
261 void CCLayerSorter::createGraphEdges()
262 {
263 #if !defined( NDEBUG )
264 LOG(CCLayerSorter, "Edges:\n");
265 #endif
266 // Fraction of the total zRange below which z differences
267 // are not considered reliable.
268 const float zThresholdFactor = 0.01;
269 float zThreshold = m_zRange * zThresholdFactor;
270
271 for (unsigned na = 0; na < m_nodes.size(); na++) {
272 GraphNode& nodeA = m_nodes[na];
273 if (!nodeA.layer->drawsContent() && !nodeA.layer->renderSurface())
274 continue;
275 for (unsigned nb = na + 1; nb < m_nodes.size(); nb++) {
276 GraphNode& nodeB = m_nodes[nb];
277 if (!nodeB.layer->drawsContent() && !nodeB.layer->renderSurface())
278 continue;
279 float weight = 0;
280 ABCompareResult overlapResult = checkOverlap(&nodeA.shape, &nodeB.sh ape, zThreshold, weight);
281 GraphNode* startNode = 0;
282 GraphNode* endNode = 0;
283 if (overlapResult == ABeforeB) {
284 startNode = &nodeA;
285 endNode = &nodeB;
286 } else if (overlapResult == BBeforeA) {
287 startNode = &nodeB;
288 endNode = &nodeA;
289 }
290
291 if (startNode) {
292 #if !defined( NDEBUG )
293 LOG(CCLayerSorter, "%d -> %d\n", startNode->layer->id(), endNode ->layer->id());
294 #endif
295 m_edges.append(GraphEdge(startNode, endNode, weight));
296 }
297 }
298 }
299
300 for (unsigned i = 0; i < m_edges.size(); i++) {
301 GraphEdge& edge = m_edges[i];
302 m_activeEdges.add(&edge, &edge);
303 edge.from->outgoing.append(&edge);
304 edge.to->incoming.append(&edge);
305 edge.to->incomingEdgeWeight += edge.weight;
306 }
307 }
308
309 // Finds and removes an edge from the list by doing a swap with the
310 // last element of the list.
311 void CCLayerSorter::removeEdgeFromList(GraphEdge* edge, Vector<GraphEdge*>& list )
312 {
313 size_t edgeIndex = list.find(edge);
314 ASSERT(edgeIndex != notFound);
315 if (list.size() == 1) {
316 ASSERT(!edgeIndex);
317 list.clear();
318 return;
319 }
320 if (edgeIndex != list.size() - 1)
321 list[edgeIndex] = list[list.size() - 1];
322
323 list.removeLast();
324 }
325
326 // Sorts the given list of layers such that they can be painted in a back-to-fro nt
327 // order. Sorting produces correct results for non-intersecting layers that don' t have
328 // cyclical order dependencies. Cycles and intersections are broken (somewhat) a ribtrarily.
329 // Sorting of layers is done via a topological sort of a directed graph whose no des are
330 // the layers themselves. An edge from node A to node B signifies that layer A n eeds to
331 // be drawn before layer B. If A and B have no dependency between each other, th en we
332 // preserve the ordering of those layers as they were in the original list.
333 //
334 // The draw order between two layers is determined by projecting the two triangl es making
335 // up each layer quad to the Z = 0 plane, finding points of intersection between the triangles
336 // and backprojecting those points to the plane of the layer to determine the co rresponding Z
337 // coordinate. The layer with the lower Z coordinate (farther from the eye) need s to be rendered
338 // first.
339 //
340 // If the layer projections don't intersect, then no edges (dependencies) are cr eated
341 // between them in the graph. HOWEVER, in this case we still need to preserve th e ordering
342 // of the original list of layers, since that list should already have proper z- index
343 // ordering of layers.
344 //
345 void CCLayerSorter::sort(LayerList::iterator first, LayerList::iterator last)
346 {
347 #if !defined( NDEBUG )
348 LOG(CCLayerSorter, "Sorting start ----\n");
349 #endif
350 createGraphNodes(first, last);
351
352 createGraphEdges();
353
354 Vector<GraphNode*> sortedList;
355 Deque<GraphNode*> noIncomingEdgeNodeList;
356
357 // Find all the nodes that don't have incoming edges.
358 for (NodeList::iterator la = m_nodes.begin(); la < m_nodes.end(); la++) {
359 if (!la->incoming.size())
360 noIncomingEdgeNodeList.append(la);
361 }
362
363 #if !defined( NDEBUG )
364 LOG(CCLayerSorter, "Sorted list: ");
365 #endif
366 while (m_activeEdges.size() || noIncomingEdgeNodeList.size()) {
367 while (noIncomingEdgeNodeList.size()) {
368
369 // It is necessary to preserve the existing ordering of layers, when there are
370 // no explicit dependencies (because this existing ordering has corr ect
371 // z-index/layout ordering). To preserve this ordering, we process N odes in
372 // the same order that they were added to the list.
373 GraphNode* fromNode = noIncomingEdgeNodeList.takeFirst();
374
375 // Add it to the final list.
376 sortedList.append(fromNode);
377
378 #if !defined( NDEBUG )
379 LOG(CCLayerSorter, "%d, ", fromNode->layer->id());
380 #endif
381
382 // Remove all its outgoing edges from the graph.
383 for (unsigned i = 0; i < fromNode->outgoing.size(); i++) {
384 GraphEdge* outgoingEdge = fromNode->outgoing[i];
385
386 m_activeEdges.remove(outgoingEdge);
387 removeEdgeFromList(outgoingEdge, outgoingEdge->to->incoming);
388 outgoingEdge->to->incomingEdgeWeight -= outgoingEdge->weight;
389
390 if (!outgoingEdge->to->incoming.size())
391 noIncomingEdgeNodeList.append(outgoingEdge->to);
392 }
393 fromNode->outgoing.clear();
394 }
395
396 if (!m_activeEdges.size())
397 break;
398
399 // If there are still active edges but the list of nodes without incomin g edges
400 // is empty then we have run into a cycle. Break the cycle by finding th e node
401 // with the smallest overall incoming edge weight and use it. This will favor
402 // nodes that have zero-weight incoming edges i.e. layers that are being
403 // occluded by a layer that intersects them.
404 float minIncomingEdgeWeight = FLT_MAX;
405 GraphNode* nextNode = 0;
406 for (unsigned i = 0; i < m_nodes.size(); i++) {
407 if (m_nodes[i].incoming.size() && m_nodes[i].incomingEdgeWeight < mi nIncomingEdgeWeight) {
408 minIncomingEdgeWeight = m_nodes[i].incomingEdgeWeight;
409 nextNode = &m_nodes[i];
410 }
411 }
412 ASSERT(nextNode);
413 // Remove all its incoming edges.
414 for (unsigned e = 0; e < nextNode->incoming.size(); e++) {
415 GraphEdge* incomingEdge = nextNode->incoming[e];
416
417 m_activeEdges.remove(incomingEdge);
418 removeEdgeFromList(incomingEdge, incomingEdge->from->outgoing);
419 }
420 nextNode->incoming.clear();
421 nextNode->incomingEdgeWeight = 0;
422 noIncomingEdgeNodeList.append(nextNode);
423 #if !defined( NDEBUG )
424 LOG(CCLayerSorter, "Breaking cycle by cleaning up incoming edges from %d (weight = %f)\n", nextNode->layer->id(), minIncomingEdgeWeight);
425 #endif
426 }
427
428 // Note: The original elements of the list are in no danger of having their ref count go to zero
429 // here as they are all nodes of the layer hierarchy and are kept alive by t heir parent nodes.
430 int count = 0;
431 for (LayerList::iterator it = first; it < last; it++)
432 *it = sortedList[count++]->layer;
433
434 #if !defined( NDEBUG )
435 LOG(CCLayerSorter, "Sorting end ----\n");
436 #endif
437
438 m_nodes.clear();
439 m_edges.clear();
440 m_activeEdges.clear();
441 }
442
443 }
OLDNEW
« no previous file with comments | « ui/cc/cc/CCLayerSorter.h ('k') | ui/cc/cc/CCLayerTilingData.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698