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

Side by Side Diff: src/gpu/GrReducedClip.cpp

Issue 653393003: Cleanup: Turn GrReducedClip into a class with a static function. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 6 years, 2 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
« src/gpu/GrReducedClip.h ('K') | « src/gpu/GrReducedClip.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1
2 /* 1 /*
3 * Copyright 2012 Google Inc. 2 * Copyright 2012 Google Inc.
4 * 3 *
5 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file. 5 * found in the LICENSE file.
7 */ 6 */
8 7
9 #include "GrReducedClip.h" 8 #include "GrReducedClip.h"
10 9
11 typedef SkClipStack::Element Element; 10 typedef SkClipStack::Element Element;
12 ////////////////////////////////////////////////////////////////////////////////
13 11
14 namespace GrReducedClip { 12 static void reduced_stack_walker(const SkClipStack& stack,
15 13 const SkRect& queryBounds,
16 // helper function 14 GrReducedClip::ElementList* result,
17 void reduced_stack_walker(const SkClipStack& stack, 15 int32_t* resultGenID,
18 const SkRect& queryBounds, 16 GrReducedClip::InitialState* initialState,
19 ElementList* result, 17 bool* requiresAA) {
20 int32_t* resultGenID,
21 InitialState* initialState,
22 bool* requiresAA);
23
24 /*
25 There are plenty of optimizations that could be added here. Maybe flips could be folded into
26 earlier operations. Or would inserting flips and reversing earlier ops ever be a win? Perhaps
27 for the case where the bounds are kInsideOut_BoundsType. We could restrict earli er operations
28 based on later intersect operations, and perhaps remove intersect-rects. We coul d optionally
29 take a rect in case the caller knows a bound on what is to be drawn through this clip.
30 */
31 void ReduceClipStack(const SkClipStack& stack,
32 const SkIRect& queryBounds,
33 ElementList* result,
34 int32_t* resultGenID,
35 InitialState* initialState,
36 SkIRect* tighterBounds,
37 bool* requiresAA) {
38 result->reset();
39
40 // The clip established by the element list might be cached based on the las t
41 // generation id. When we make early returns, we do not know what was the ge neration
42 // id that lead to the state. Make a conservative guess.
43 *resultGenID = stack.getTopmostGenID();
44
45 if (stack.isWideOpen()) {
46 *initialState = kAllIn_InitialState;
47 return;
48 }
49
50
51 // We initially look at whether the bounds alone is sufficient. We also use the stack bounds to
52 // attempt to compute the tighterBounds.
53
54 SkClipStack::BoundsType stackBoundsType;
55 SkRect stackBounds;
56 bool iior;
57 stack.getBounds(&stackBounds, &stackBoundsType, &iior);
58
59 const SkIRect* bounds = &queryBounds;
60
61 SkRect scalarQueryBounds = SkRect::Make(queryBounds);
62
63 if (iior) {
64 SkASSERT(SkClipStack::kNormal_BoundsType == stackBoundsType);
65 SkRect isectRect;
66 if (stackBounds.contains(scalarQueryBounds)) {
67 *initialState = kAllIn_InitialState;
68 if (tighterBounds) {
69 *tighterBounds = queryBounds;
70 }
71 if (requiresAA) {
72 *requiresAA = false;
73 }
74 } else if (isectRect.intersect(stackBounds, scalarQueryBounds)) {
75 // If the caller asked for tighter integer bounds we may be able to
76 // return kAllIn and give the bounds with no elements
77 if (tighterBounds) {
78 isectRect.roundOut(tighterBounds);
79 SkRect scalarTighterBounds = SkRect::Make(*tighterBounds);
80 if (scalarTighterBounds == isectRect) {
81 // the round-out didn't add any area outside the clip rect.
82 if (requiresAA) {
83 *requiresAA = false;
84 }
85 *initialState = kAllIn_InitialState;
86 return;
87 }
88 }
89 *initialState = kAllOut_InitialState;
90 // iior should only be true if aa/non-aa status matches among all el ements.
91 SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
92 bool doAA = iter.prev()->isAA();
93 SkNEW_INSERT_AT_LLIST_HEAD(result, Element, (isectRect, SkRegion::kR eplace_Op, doAA));
94 if (requiresAA) {
95 *requiresAA = doAA;
96 }
97 } else {
98 *initialState = kAllOut_InitialState;
99 if (requiresAA) {
100 *requiresAA = false;
101 }
102 }
103 return;
104 } else {
105 if (SkClipStack::kNormal_BoundsType == stackBoundsType) {
106 if (!SkRect::Intersects(stackBounds, scalarQueryBounds)) {
107 *initialState = kAllOut_InitialState;
108 if (requiresAA) {
109 *requiresAA = false;
110 }
111 return;
112 }
113 if (tighterBounds) {
114 SkIRect stackIBounds;
115 stackBounds.roundOut(&stackIBounds);
116 tighterBounds->intersect(queryBounds, stackIBounds);
117 bounds = tighterBounds;
118 }
119 } else {
120 if (stackBounds.contains(scalarQueryBounds)) {
121 *initialState = kAllOut_InitialState;
122 if (requiresAA) {
123 *requiresAA = false;
124 }
125 return;
126 }
127 if (tighterBounds) {
128 *tighterBounds = queryBounds;
129 }
130 }
131 }
132
133 SkRect scalarBounds = SkRect::Make(*bounds);
134
135 // Now that we have determined the bounds to use and filtered out the trivia l cases, call the
136 // helper that actually walks the stack.
137 reduced_stack_walker(stack, scalarBounds, result, resultGenID, initialState, requiresAA);
138
139 // The list that was computed in this function may be cached based on the ge n id of the last
140 // element.
141 SkASSERT(SkClipStack::kInvalidGenID != *resultGenID);
142 }
143
144 void reduced_stack_walker(const SkClipStack& stack,
145 const SkRect& queryBounds,
146 ElementList* result,
147 int32_t* resultGenID,
148 InitialState* initialState,
149 bool* requiresAA) {
150 18
151 // walk backwards until we get to: 19 // walk backwards until we get to:
152 // a) the beginning 20 // a) the beginning
153 // b) an operation that is known to make the bounds all inside/outside 21 // b) an operation that is known to make the bounds all inside/outside
154 // c) a replace operation 22 // c) a replace operation
155 23
robertphillips 2014/10/23 12:24:17 overlength ?
tfarina 2014/10/24 00:38:57 Done.
156 static const InitialState kUnknown_InitialState = static_cast<InitialState>( -1); 24 static const GrReducedClip::InitialState kUnknown_InitialState = static_cast <GrReducedClip::InitialState>(-1);
157 *initialState = kUnknown_InitialState; 25 *initialState = kUnknown_InitialState;
158 26
159 // During our backwards walk, track whether we've seen ops that either grow or shrink the clip. 27 // During our backwards walk, track whether we've seen ops that either grow or shrink the clip.
160 // TODO: track these per saved clip so that we can consider them on the forw ard pass. 28 // TODO: track these per saved clip so that we can consider them on the forw ard pass.
161 bool embiggens = false; 29 bool embiggens = false;
162 bool emsmallens = false; 30 bool emsmallens = false;
163 31
164 SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart); 32 SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
165 int numAAElements = 0; 33 int numAAElements = 0;
166 while ((kUnknown_InitialState == *initialState)) { 34 while ((kUnknown_InitialState == *initialState)) {
167 const Element* element = iter.prev(); 35 const Element* element = iter.prev();
168 if (NULL == element) { 36 if (NULL == element) {
169 *initialState = kAllIn_InitialState; 37 *initialState = GrReducedClip::kAllIn_InitialState;
170 break; 38 break;
171 } 39 }
172 if (SkClipStack::kEmptyGenID == element->getGenID()) { 40 if (SkClipStack::kEmptyGenID == element->getGenID()) {
173 *initialState = kAllOut_InitialState; 41 *initialState = GrReducedClip::kAllOut_InitialState;
174 break; 42 break;
175 } 43 }
176 if (SkClipStack::kWideOpenGenID == element->getGenID()) { 44 if (SkClipStack::kWideOpenGenID == element->getGenID()) {
177 *initialState = kAllIn_InitialState; 45 *initialState = GrReducedClip::kAllIn_InitialState;
178 break; 46 break;
179 } 47 }
180 48
181 bool skippable = false; 49 bool skippable = false;
182 bool isFlip = false; // does this op just flip the in/out state of every point in the bounds 50 bool isFlip = false; // does this op just flip the in/out state of every point in the bounds
183 51
184 switch (element->getOp()) { 52 switch (element->getOp()) {
185 case SkRegion::kDifference_Op: 53 case SkRegion::kDifference_Op:
186 // check if the shape subtracted either contains the entire boun ds (and makes 54 // check if the shape subtracted either contains the entire boun ds (and makes
187 // the clip empty) or is outside the bounds and therefore can be skipped. 55 // the clip empty) or is outside the bounds and therefore can be skipped.
188 if (element->isInverseFilled()) { 56 if (element->isInverseFilled()) {
189 if (element->contains(queryBounds)) { 57 if (element->contains(queryBounds)) {
190 skippable = true; 58 skippable = true;
191 } else if (!SkRect::Intersects(element->getBounds(), queryBo unds)) { 59 } else if (!SkRect::Intersects(element->getBounds(), queryBo unds)) {
192 *initialState = kAllOut_InitialState; 60 *initialState = GrReducedClip::kAllOut_InitialState;
193 skippable = true; 61 skippable = true;
194 } 62 }
195 } else { 63 } else {
196 if (element->contains(queryBounds)) { 64 if (element->contains(queryBounds)) {
197 *initialState = kAllOut_InitialState; 65 *initialState = GrReducedClip::kAllOut_InitialState;
198 skippable = true; 66 skippable = true;
199 } else if (!SkRect::Intersects(element->getBounds(), queryBo unds)) { 67 } else if (!SkRect::Intersects(element->getBounds(), queryBo unds)) {
200 skippable = true; 68 skippable = true;
201 } 69 }
202 } 70 }
203 if (!skippable) { 71 if (!skippable) {
204 emsmallens = true; 72 emsmallens = true;
205 } 73 }
206 break; 74 break;
207 case SkRegion::kIntersect_Op: 75 case SkRegion::kIntersect_Op:
208 // check if the shape intersected contains the entire bounds and therefore can 76 // check if the shape intersected contains the entire bounds and therefore can
209 // be skipped or it is outside the entire bounds and therefore m akes the clip 77 // be skipped or it is outside the entire bounds and therefore m akes the clip
210 // empty. 78 // empty.
211 if (element->isInverseFilled()) { 79 if (element->isInverseFilled()) {
212 if (element->contains(queryBounds)) { 80 if (element->contains(queryBounds)) {
213 *initialState = kAllOut_InitialState; 81 *initialState = GrReducedClip::kAllOut_InitialState;
214 skippable = true; 82 skippable = true;
215 } else if (!SkRect::Intersects(element->getBounds(), queryBo unds)) { 83 } else if (!SkRect::Intersects(element->getBounds(), queryBo unds)) {
216 skippable = true; 84 skippable = true;
217 } 85 }
218 } else { 86 } else {
219 if (element->contains(queryBounds)) { 87 if (element->contains(queryBounds)) {
220 skippable = true; 88 skippable = true;
221 } else if (!SkRect::Intersects(element->getBounds(), queryBo unds)) { 89 } else if (!SkRect::Intersects(element->getBounds(), queryBo unds)) {
222 *initialState = kAllOut_InitialState; 90 *initialState = GrReducedClip::kAllOut_InitialState;
223 skippable = true; 91 skippable = true;
224 } 92 }
225 } 93 }
226 if (!skippable) { 94 if (!skippable) {
227 emsmallens = true; 95 emsmallens = true;
228 } 96 }
229 break; 97 break;
230 case SkRegion::kUnion_Op: 98 case SkRegion::kUnion_Op:
231 // If the union-ed shape contains the entire bounds then after t his element 99 // If the union-ed shape contains the entire bounds then after t his element
232 // the bounds is entirely inside the clip. If the union-ed shape is outside the 100 // the bounds is entirely inside the clip. If the union-ed shape is outside the
233 // bounds then this op can be skipped. 101 // bounds then this op can be skipped.
234 if (element->isInverseFilled()) { 102 if (element->isInverseFilled()) {
235 if (element->contains(queryBounds)) { 103 if (element->contains(queryBounds)) {
236 skippable = true; 104 skippable = true;
237 } else if (!SkRect::Intersects(element->getBounds(), queryBo unds)) { 105 } else if (!SkRect::Intersects(element->getBounds(), queryBo unds)) {
238 *initialState = kAllIn_InitialState; 106 *initialState = GrReducedClip::kAllIn_InitialState;
239 skippable = true; 107 skippable = true;
240 } 108 }
241 } else { 109 } else {
242 if (element->contains(queryBounds)) { 110 if (element->contains(queryBounds)) {
243 *initialState = kAllIn_InitialState; 111 *initialState = GrReducedClip::kAllIn_InitialState;
244 skippable = true; 112 skippable = true;
245 } else if (!SkRect::Intersects(element->getBounds(), queryBo unds)) { 113 } else if (!SkRect::Intersects(element->getBounds(), queryBo unds)) {
246 skippable = true; 114 skippable = true;
247 } 115 }
248 } 116 }
249 if (!skippable) { 117 if (!skippable) {
250 embiggens = true; 118 embiggens = true;
251 } 119 }
252 break; 120 break;
253 case SkRegion::kXOR_Op: 121 case SkRegion::kXOR_Op:
(...skipping 18 matching lines...) Expand all
272 emsmallens = embiggens = true; 140 emsmallens = embiggens = true;
273 } 141 }
274 break; 142 break;
275 case SkRegion::kReverseDifference_Op: 143 case SkRegion::kReverseDifference_Op:
276 // When the bounds is entirely within the rev-diff shape then th is behaves like xor 144 // When the bounds is entirely within the rev-diff shape then th is behaves like xor
277 // and reverses every point inside the bounds. If the shape is c ompletely outside 145 // and reverses every point inside the bounds. If the shape is c ompletely outside
278 // the bounds then we know after this element is applied that th e bounds will be 146 // the bounds then we know after this element is applied that th e bounds will be
279 // all outside the current clip.B 147 // all outside the current clip.B
280 if (element->isInverseFilled()) { 148 if (element->isInverseFilled()) {
281 if (element->contains(queryBounds)) { 149 if (element->contains(queryBounds)) {
282 *initialState = kAllOut_InitialState; 150 *initialState = GrReducedClip::kAllOut_InitialState;
283 skippable = true; 151 skippable = true;
284 } else if (!SkRect::Intersects(element->getBounds(), queryBo unds)) { 152 } else if (!SkRect::Intersects(element->getBounds(), queryBo unds)) {
285 isFlip = true; 153 isFlip = true;
286 } 154 }
287 } else { 155 } else {
288 if (element->contains(queryBounds)) { 156 if (element->contains(queryBounds)) {
289 isFlip = true; 157 isFlip = true;
290 } else if (!SkRect::Intersects(element->getBounds(), queryBo unds)) { 158 } else if (!SkRect::Intersects(element->getBounds(), queryBo unds)) {
291 *initialState = kAllOut_InitialState; 159 *initialState = GrReducedClip::kAllOut_InitialState;
292 skippable = true; 160 skippable = true;
293 } 161 }
294 } 162 }
295 if (!skippable) { 163 if (!skippable) {
296 emsmallens = embiggens = true; 164 emsmallens = embiggens = true;
297 } 165 }
298 break; 166 break;
299 case SkRegion::kReplace_Op: 167 case SkRegion::kReplace_Op:
300 // Replace will always terminate our walk. We will either begin the forward walk 168 // Replace will always terminate our walk. We will either begin the forward walk
301 // at the replace op or detect here than the shape is either com pletely inside 169 // at the replace op or detect here than the shape is either com pletely inside
302 // or completely outside the bounds. In this latter case it can be skipped by 170 // or completely outside the bounds. In this latter case it can be skipped by
303 // setting the correct value for initialState. 171 // setting the correct value for initialState.
304 if (element->isInverseFilled()) { 172 if (element->isInverseFilled()) {
305 if (element->contains(queryBounds)) { 173 if (element->contains(queryBounds)) {
306 *initialState = kAllOut_InitialState; 174 *initialState = GrReducedClip::kAllOut_InitialState;
307 skippable = true; 175 skippable = true;
308 } else if (!SkRect::Intersects(element->getBounds(), queryBo unds)) { 176 } else if (!SkRect::Intersects(element->getBounds(), queryBo unds)) {
309 *initialState = kAllIn_InitialState; 177 *initialState = GrReducedClip::kAllIn_InitialState;
310 skippable = true; 178 skippable = true;
311 } 179 }
312 } else { 180 } else {
313 if (element->contains(queryBounds)) { 181 if (element->contains(queryBounds)) {
314 *initialState = kAllIn_InitialState; 182 *initialState = GrReducedClip::kAllIn_InitialState;
315 skippable = true; 183 skippable = true;
316 } else if (!SkRect::Intersects(element->getBounds(), queryBo unds)) { 184 } else if (!SkRect::Intersects(element->getBounds(), queryBo unds)) {
317 *initialState = kAllOut_InitialState; 185 *initialState = GrReducedClip::kAllOut_InitialState;
318 skippable = true; 186 skippable = true;
319 } 187 }
320 } 188 }
321 if (!skippable) { 189 if (!skippable) {
322 *initialState = kAllOut_InitialState; 190 *initialState = GrReducedClip::kAllOut_InitialState;
323 embiggens = emsmallens = true; 191 embiggens = emsmallens = true;
324 } 192 }
325 break; 193 break;
326 default: 194 default:
327 SkDEBUGFAIL("Unexpected op."); 195 SkDEBUGFAIL("Unexpected op.");
328 break; 196 break;
329 } 197 }
330 if (!skippable) { 198 if (!skippable) {
331 if (0 == result->count()) { 199 if (0 == result->count()) {
332 // This will be the last element. Record the stricter genID. 200 // This will be the last element. Record the stricter genID.
(...skipping 14 matching lines...) Expand all
347 } 215 }
348 // Intersecting an inverse shape is the same as differencing the non-inverse shape. 216 // Intersecting an inverse shape is the same as differencing the non-inverse shape.
349 // Replacing with an inverse shape is the same as setting initia lState=kAllIn and 217 // Replacing with an inverse shape is the same as setting initia lState=kAllIn and
350 // differencing the non-inverse shape. 218 // differencing the non-inverse shape.
351 bool isReplace = SkRegion::kReplace_Op == newElement->getOp(); 219 bool isReplace = SkRegion::kReplace_Op == newElement->getOp();
352 if (newElement->isInverseFilled() && 220 if (newElement->isInverseFilled() &&
353 (SkRegion::kIntersect_Op == newElement->getOp() || isReplace )) { 221 (SkRegion::kIntersect_Op == newElement->getOp() || isReplace )) {
354 newElement->invertShapeFillType(); 222 newElement->invertShapeFillType();
355 newElement->setOp(SkRegion::kDifference_Op); 223 newElement->setOp(SkRegion::kDifference_Op);
356 if (isReplace) { 224 if (isReplace) {
357 SkASSERT(kAllOut_InitialState == *initialState); 225 SkASSERT(GrReducedClip::kAllOut_InitialState == *initial State);
358 *initialState = kAllIn_InitialState; 226 *initialState = GrReducedClip::kAllIn_InitialState;
359 } 227 }
360 } 228 }
361 } 229 }
362 } 230 }
363 } 231 }
364 232
365 if ((kAllOut_InitialState == *initialState && !embiggens) || 233 if ((GrReducedClip::kAllOut_InitialState == *initialState && !embiggens) ||
366 (kAllIn_InitialState == *initialState && !emsmallens)) { 234 (GrReducedClip::kAllIn_InitialState == *initialState && !emsmallens)) {
367 result->reset(); 235 result->reset();
368 } else { 236 } else {
369 Element* element = result->headIter().get(); 237 Element* element = result->headIter().get();
370 while (element) { 238 while (element) {
371 bool skippable = false; 239 bool skippable = false;
372 switch (element->getOp()) { 240 switch (element->getOp()) {
373 case SkRegion::kDifference_Op: 241 case SkRegion::kDifference_Op:
374 // subtracting from the empty set yields the empty set. 242 // subtracting from the empty set yields the empty set.
375 skippable = kAllOut_InitialState == *initialState; 243 skippable = GrReducedClip::kAllOut_InitialState == *initialS tate;
376 break; 244 break;
377 case SkRegion::kIntersect_Op: 245 case SkRegion::kIntersect_Op:
378 // intersecting with the empty set yields the empty set 246 // intersecting with the empty set yields the empty set
379 if (kAllOut_InitialState == *initialState) { 247 if (GrReducedClip::kAllOut_InitialState == *initialState) {
380 skippable = true; 248 skippable = true;
381 } else { 249 } else {
382 // We can clear to zero and then simply draw the clip el ement. 250 // We can clear to zero and then simply draw the clip el ement.
383 *initialState = kAllOut_InitialState; 251 *initialState = GrReducedClip::kAllOut_InitialState;
384 element->setOp(SkRegion::kReplace_Op); 252 element->setOp(SkRegion::kReplace_Op);
385 } 253 }
386 break; 254 break;
387 case SkRegion::kUnion_Op: 255 case SkRegion::kUnion_Op:
388 if (kAllIn_InitialState == *initialState) { 256 if (GrReducedClip::kAllIn_InitialState == *initialState) {
389 // unioning the infinite plane with anything is a no-op. 257 // unioning the infinite plane with anything is a no-op.
390 skippable = true; 258 skippable = true;
391 } else { 259 } else {
392 // unioning the empty set with a shape is the shape. 260 // unioning the empty set with a shape is the shape.
393 element->setOp(SkRegion::kReplace_Op); 261 element->setOp(SkRegion::kReplace_Op);
394 } 262 }
395 break; 263 break;
396 case SkRegion::kXOR_Op: 264 case SkRegion::kXOR_Op:
397 if (kAllOut_InitialState == *initialState) { 265 if (GrReducedClip::kAllOut_InitialState == *initialState) {
398 // xor could be changed to diff in the kAllIn case, not sure it's a win. 266 // xor could be changed to diff in the kAllIn case, not sure it's a win.
399 element->setOp(SkRegion::kReplace_Op); 267 element->setOp(SkRegion::kReplace_Op);
400 } 268 }
401 break; 269 break;
402 case SkRegion::kReverseDifference_Op: 270 case SkRegion::kReverseDifference_Op:
403 if (kAllIn_InitialState == *initialState) { 271 if (GrReducedClip::kAllIn_InitialState == *initialState) {
404 // subtracting the whole plane will yield the empty set. 272 // subtracting the whole plane will yield the empty set.
405 skippable = true; 273 skippable = true;
406 *initialState = kAllOut_InitialState; 274 *initialState = GrReducedClip::kAllOut_InitialState;
407 } else { 275 } else {
408 // this picks up flips inserted in the backwards pass. 276 // this picks up flips inserted in the backwards pass.
409 skippable = element->isInverseFilled() ? 277 skippable = element->isInverseFilled() ?
410 !SkRect::Intersects(element->getBounds(), queryBound s) : 278 !SkRect::Intersects(element->getBounds(), queryBound s) :
411 element->contains(queryBounds); 279 element->contains(queryBounds);
412 if (skippable) { 280 if (skippable) {
413 *initialState = kAllIn_InitialState; 281 *initialState = GrReducedClip::kAllIn_InitialState;
414 } else { 282 } else {
415 element->setOp(SkRegion::kReplace_Op); 283 element->setOp(SkRegion::kReplace_Op);
416 } 284 }
417 } 285 }
418 break; 286 break;
419 case SkRegion::kReplace_Op: 287 case SkRegion::kReplace_Op:
420 skippable = false; // we would have skipped it in the backwa rds walk if we 288 skippable = false; // we would have skipped it in the backwa rds walk if we
421 // could've. 289 // could've.
422 break; 290 break;
423 default: 291 default:
424 SkDEBUGFAIL("Unexpected op."); 292 SkDEBUGFAIL("Unexpected op.");
425 break; 293 break;
426 } 294 }
427 if (!skippable) { 295 if (!skippable) {
428 break; 296 break;
429 } else { 297 } else {
430 if (element->isAA()) { 298 if (element->isAA()) {
431 --numAAElements; 299 --numAAElements;
432 } 300 }
433 result->popHead(); 301 result->popHead();
434 element = result->headIter().get(); 302 element = result->headIter().get();
435 } 303 }
436 } 304 }
437 } 305 }
438 if (requiresAA) { 306 if (requiresAA) {
439 *requiresAA = numAAElements > 0; 307 *requiresAA = numAAElements > 0;
440 } 308 }
441 309
442 if (0 == result->count()) { 310 if (0 == result->count()) {
443 if (*initialState == kAllIn_InitialState) { 311 if (*initialState == GrReducedClip::kAllIn_InitialState) {
444 *resultGenID = SkClipStack::kWideOpenGenID; 312 *resultGenID = SkClipStack::kWideOpenGenID;
445 } else { 313 } else {
446 *resultGenID = SkClipStack::kEmptyGenID; 314 *resultGenID = SkClipStack::kEmptyGenID;
447 } 315 }
448 } 316 }
449 } 317 }
450 } // namespace GrReducedClip 318
319 /*
320 There are plenty of optimizations that could be added here. Maybe flips could be folded into
321 earlier operations. Or would inserting flips and reversing earlier ops ever be a win? Perhaps
322 for the case where the bounds are kInsideOut_BoundsType. We could restrict earli er operations
323 based on later intersect operations, and perhaps remove intersect-rects. We coul d optionally
324 take a rect in case the caller knows a bound on what is to be drawn through this clip.
325 */
326 void GrReducedClip::ReduceClipStack(const SkClipStack& stack,
tfarina 2014/10/23 04:03:08 Sorry for this big diff. I can revert if you want.
327 const SkIRect& queryBounds,
328 ElementList* result,
329 int32_t* resultGenID,
330 InitialState* initialState,
331 SkIRect* tighterBounds,
332 bool* requiresAA) {
333 result->reset();
334
335 // The clip established by the element list might be cached based on the las t
336 // generation id. When we make early returns, we do not know what was the ge neration
337 // id that lead to the state. Make a conservative guess.
338 *resultGenID = stack.getTopmostGenID();
339
340 if (stack.isWideOpen()) {
341 *initialState = kAllIn_InitialState;
342 return;
343 }
344
345
346 // We initially look at whether the bounds alone is sufficient. We also use the stack bounds to
347 // attempt to compute the tighterBounds.
348
349 SkClipStack::BoundsType stackBoundsType;
350 SkRect stackBounds;
351 bool iior;
352 stack.getBounds(&stackBounds, &stackBoundsType, &iior);
353
354 const SkIRect* bounds = &queryBounds;
355
356 SkRect scalarQueryBounds = SkRect::Make(queryBounds);
357
358 if (iior) {
359 SkASSERT(SkClipStack::kNormal_BoundsType == stackBoundsType);
360 SkRect isectRect;
361 if (stackBounds.contains(scalarQueryBounds)) {
362 *initialState = GrReducedClip::kAllIn_InitialState;
363 if (tighterBounds) {
364 *tighterBounds = queryBounds;
365 }
366 if (requiresAA) {
367 *requiresAA = false;
368 }
369 } else if (isectRect.intersect(stackBounds, scalarQueryBounds)) {
370 // If the caller asked for tighter integer bounds we may be able to
371 // return kAllIn and give the bounds with no elements
372 if (tighterBounds) {
373 isectRect.roundOut(tighterBounds);
374 SkRect scalarTighterBounds = SkRect::Make(*tighterBounds);
375 if (scalarTighterBounds == isectRect) {
376 // the round-out didn't add any area outside the clip rect.
377 if (requiresAA) {
378 *requiresAA = false;
379 }
380 *initialState = GrReducedClip::kAllIn_InitialState;
381 return;
382 }
383 }
384 *initialState = kAllOut_InitialState;
385 // iior should only be true if aa/non-aa status matches among all el ements.
386 SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
387 bool doAA = iter.prev()->isAA();
388 SkNEW_INSERT_AT_LLIST_HEAD(result, Element, (isectRect, SkRegion::kR eplace_Op, doAA));
389 if (requiresAA) {
390 *requiresAA = doAA;
391 }
392 } else {
393 *initialState = kAllOut_InitialState;
394 if (requiresAA) {
395 *requiresAA = false;
396 }
397 }
398 return;
399 } else {
400 if (SkClipStack::kNormal_BoundsType == stackBoundsType) {
401 if (!SkRect::Intersects(stackBounds, scalarQueryBounds)) {
402 *initialState = kAllOut_InitialState;
403 if (requiresAA) {
404 *requiresAA = false;
405 }
406 return;
407 }
408 if (tighterBounds) {
409 SkIRect stackIBounds;
410 stackBounds.roundOut(&stackIBounds);
411 tighterBounds->intersect(queryBounds, stackIBounds);
412 bounds = tighterBounds;
413 }
414 } else {
415 if (stackBounds.contains(scalarQueryBounds)) {
416 *initialState = kAllOut_InitialState;
417 if (requiresAA) {
418 *requiresAA = false;
419 }
420 return;
421 }
422 if (tighterBounds) {
423 *tighterBounds = queryBounds;
424 }
425 }
426 }
427
428 SkRect scalarBounds = SkRect::Make(*bounds);
429
430 // Now that we have determined the bounds to use and filtered out the trivia l cases, call the
431 // helper that actually walks the stack.
432 reduced_stack_walker(stack, scalarBounds, result, resultGenID, initialState, requiresAA);
433
434 // The list that was computed in this function may be cached based on the ge n id of the last
435 // element.
436 SkASSERT(SkClipStack::kInvalidGenID != *resultGenID);
437 }
OLDNEW
« src/gpu/GrReducedClip.h ('K') | « src/gpu/GrReducedClip.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698