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

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

Powered by Google App Engine
This is Rietveld 408576698