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

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

Issue 2271493002: Skip non-AA intersect rects in GrReducedClip (Closed) Base URL: https://skia.googlesource.com/skia.git@upload2_uploadnocliptomaskoffset
Patch Set: rebase, remove dependency Created 4 years, 4 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 /* 1 /*
2 * Copyright 2016 Google Inc. 2 * Copyright 2016 Google Inc.
3 * 3 *
4 * 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
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "GrReducedClip.h" 8 #include "GrReducedClip.h"
9 9
10 #include "GrClip.h" 10 #include "GrClip.h"
11 11
12 typedef SkClipStack::Element Element; 12 typedef SkClipStack::Element Element;
13 13
14 static GrReducedClip::InitialState reduced_stack_walker(const SkClipStack& stack , 14 /**
15 const SkRect& queryBound s, 15 * There are plenty of optimizations that could be added here. Maybe flips could be folded into
16 const SkIRect& clipIBoun ds, 16 * earlier operations. Or would inserting flips and reversing earlier ops ever b e a win? Perhaps
17 GrReducedClip::ElementLi st* result, 17 * for the case where the bounds are kInsideOut_BoundsType. We could restrict ea rlier operations
18 int32_t* resultGenID, 18 * based on later intersect operations, and perhaps remove intersect-rects. We c ould optionally
19 bool* requiresAA) { 19 * take a rect in case the caller knows a bound on what is to be drawn through t his clip.
20 */
21 GrReducedClip::GrReducedClip(const SkClipStack& stack, const SkRect& queryBounds ) {
22 SkASSERT(!queryBounds.isEmpty());
23 fHasIBounds = false;
20 24
25 if (stack.isWideOpen()) {
26 fInitialState = InitialState::kAllIn;
27 return;
28 }
29
30 SkClipStack::BoundsType stackBoundsType;
31 SkRect stackBounds;
32 bool iior;
33 stack.getBounds(&stackBounds, &stackBoundsType, &iior);
34
35 if (stackBounds.isEmpty() || GrClip::IsOutsideClip(stackBounds, queryBounds) ) {
36 bool insideOut = SkClipStack::kInsideOut_BoundsType == stackBoundsType;
37 fInitialState = insideOut ? InitialState::kAllIn : InitialState::kAllOut ;
38 return;
39 }
40
41 if (iior) {
42 // "Is intersection of rects" means the clip is a single rect indicated by the stack bounds.
43 // This should only be true if aa/non-aa status matches among all elemen ts.
44 SkASSERT(SkClipStack::kNormal_BoundsType == stackBoundsType);
45 SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
46 if (!iter.prev()->isAA() || GrClip::IsPixelAligned(stackBounds)) {
47 // The clip is a non-aa rect. This is the one spot where we can actu ally implement the
48 // clip (using fIBounds) rather than just telling the caller what it should be.
49 stackBounds.round(&fIBounds);
50 fHasIBounds = true;
51 fInitialState = fIBounds.isEmpty() ? InitialState::kAllOut : Initial State::kAllIn;
52 return;
53 }
54 if (GrClip::IsInsideClip(stackBounds, queryBounds)) {
55 fInitialState = InitialState::kAllIn;
56 return;
57 }
58
59 SkRect tightBounds;
60 SkAssertResult(tightBounds.intersect(stackBounds, queryBounds));
61 fIBounds = GrClip::GetPixelIBounds(tightBounds);
62 SkASSERT(!fIBounds.isEmpty()); // Empty should have been blocked by IsOu tsideClip above.
63 fHasIBounds = true;
64
65 // Implement the clip with an AA rect element.
66 fElements.addToHead(stackBounds, SkRegion::kReplace_Op, true/*doAA*/);
67 fElementsGenID = stack.getTopmostGenID();
68 fRequiresAA = true;
69
70 fInitialState = InitialState::kAllOut;
71 return;
72 }
73
74 SkRect tighterQuery = queryBounds;
75 if (SkClipStack::kNormal_BoundsType == stackBoundsType) {
76 // Tighten the query by introducing a new clip at the stack's pixel boun daries. (This new
77 // clip will be enforced by the scissor through fIBounds.)
78 SkAssertResult(tighterQuery.intersect(GrClip::GetPixelBounds(stackBounds )));
79 }
80
81 fIBounds = GrClip::GetPixelIBounds(tighterQuery);
82 SkASSERT(!fIBounds.isEmpty()); // Empty should have been blocked by IsOutsid eClip above.
83 fHasIBounds = true;
84
85 // Now that we have determined the bounds to use and filtered out the trivia l cases, call the
86 // helper that actually walks the stack.
87 this->walkStack(stack, tighterQuery);
88 }
89
90 void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBound s) {
21 // walk backwards until we get to: 91 // walk backwards until we get to:
22 // a) the beginning 92 // a) the beginning
23 // b) an operation that is known to make the bounds all inside/outside 93 // b) an operation that is known to make the bounds all inside/outside
24 // c) a replace operation 94 // c) a replace operation
25 95
26 enum class InitialTriState { 96 enum class InitialTriState {
27 kUnknown = -1, 97 kUnknown = -1,
28 kAllIn = (int)GrReducedClip::InitialState::kAllIn, 98 kAllIn = (int)GrReducedClip::InitialState::kAllIn,
29 kAllOut = (int)GrReducedClip::InitialState::kAllOut 99 kAllOut = (int)GrReducedClip::InitialState::kAllOut
30 } initialState = InitialTriState::kUnknown; 100 } initialTriState = InitialTriState::kUnknown;
31 101
32 // During our backwards walk, track whether we've seen ops that either grow or shrink the clip. 102 // During our backwards walk, track whether we've seen ops that either grow or shrink the clip.
33 // TODO: track these per saved clip so that we can consider them on the forw ard pass. 103 // TODO: track these per saved clip so that we can consider them on the forw ard pass.
34 bool embiggens = false; 104 bool embiggens = false;
35 bool emsmallens = false; 105 bool emsmallens = false;
36 106
37 // We use a slightly relaxed set of query bounds for element containment tes ts. This is to 107 // We use a slightly relaxed set of query bounds for element containment tes ts. This is to
38 // account for floating point rounding error that may have occurred during c oord transforms. 108 // account for floating point rounding error that may have occurred during c oord transforms.
39 SkRect relaxedQueryBounds = queryBounds.makeInset(GrClip::kBoundsTolerance, 109 SkRect relaxedQueryBounds = queryBounds.makeInset(GrClip::kBoundsTolerance,
40 GrClip::kBoundsTolerance); 110 GrClip::kBoundsTolerance);
41 111
42 SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart); 112 SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
43 int numAAElements = 0; 113 int numAAElements = 0;
44 while (InitialTriState::kUnknown == initialState) { 114 while (InitialTriState::kUnknown == initialTriState) {
45 const Element* element = iter.prev(); 115 const Element* element = iter.prev();
46 if (nullptr == element) { 116 if (nullptr == element) {
47 initialState = InitialTriState::kAllIn; 117 initialTriState = InitialTriState::kAllIn;
48 break; 118 break;
49 } 119 }
50 if (SkClipStack::kEmptyGenID == element->getGenID()) { 120 if (SkClipStack::kEmptyGenID == element->getGenID()) {
51 initialState = InitialTriState::kAllOut; 121 initialTriState = InitialTriState::kAllOut;
52 break; 122 break;
53 } 123 }
54 if (SkClipStack::kWideOpenGenID == element->getGenID()) { 124 if (SkClipStack::kWideOpenGenID == element->getGenID()) {
55 initialState = InitialTriState::kAllIn; 125 initialTriState = InitialTriState::kAllIn;
56 break; 126 break;
57 } 127 }
58 128
59 bool skippable = false; 129 bool skippable = false;
60 bool isFlip = false; // does this op just flip the in/out state of every point in the bounds 130 bool isFlip = false; // does this op just flip the in/out state of every point in the bounds
61 131
62 switch (element->getOp()) { 132 switch (element->getOp()) {
63 case SkRegion::kDifference_Op: 133 case SkRegion::kDifference_Op:
64 // check if the shape subtracted either contains the entire boun ds (and makes 134 // check if the shape subtracted either contains the entire boun ds (and makes
65 // the clip empty) or is outside the bounds and therefore can be skipped. 135 // the clip empty) or is outside the bounds and therefore can be skipped.
66 if (element->isInverseFilled()) { 136 if (element->isInverseFilled()) {
67 if (element->contains(relaxedQueryBounds)) { 137 if (element->contains(relaxedQueryBounds)) {
68 skippable = true; 138 skippable = true;
69 } else if (GrClip::IsOutsideClip(element->getBounds(), query Bounds)) { 139 } else if (GrClip::IsOutsideClip(element->getBounds(), query Bounds)) {
70 initialState = InitialTriState::kAllOut; 140 initialTriState = InitialTriState::kAllOut;
71 skippable = true; 141 skippable = true;
72 } 142 }
73 } else { 143 } else {
74 if (element->contains(relaxedQueryBounds)) { 144 if (element->contains(relaxedQueryBounds)) {
75 initialState = InitialTriState::kAllOut; 145 initialTriState = InitialTriState::kAllOut;
76 skippable = true; 146 skippable = true;
77 } else if (GrClip::IsOutsideClip(element->getBounds(), query Bounds)) { 147 } else if (GrClip::IsOutsideClip(element->getBounds(), query Bounds)) {
78 skippable = true; 148 skippable = true;
79 } 149 }
80 } 150 }
81 if (!skippable) { 151 if (!skippable) {
82 emsmallens = true; 152 emsmallens = true;
83 } 153 }
84 break; 154 break;
85 case SkRegion::kIntersect_Op: 155 case SkRegion::kIntersect_Op:
86 // check if the shape intersected contains the entire bounds and therefore can 156 // check if the shape intersected contains the entire bounds and therefore can
87 // be skipped or it is outside the entire bounds and therefore m akes the clip 157 // be skipped or it is outside the entire bounds and therefore m akes the clip
88 // empty. 158 // empty.
89 if (element->isInverseFilled()) { 159 if (element->isInverseFilled()) {
90 if (element->contains(relaxedQueryBounds)) { 160 if (element->contains(relaxedQueryBounds)) {
91 initialState = InitialTriState::kAllOut; 161 initialTriState = InitialTriState::kAllOut;
92 skippable = true; 162 skippable = true;
93 } else if (GrClip::IsOutsideClip(element->getBounds(), query Bounds)) { 163 } else if (GrClip::IsOutsideClip(element->getBounds(), query Bounds)) {
94 skippable = true; 164 skippable = true;
95 } 165 }
96 } else { 166 } else {
97 if (element->contains(relaxedQueryBounds)) { 167 if (element->contains(relaxedQueryBounds)) {
98 skippable = true; 168 skippable = true;
99 } else if (GrClip::IsOutsideClip(element->getBounds(), query Bounds)) { 169 } else if (GrClip::IsOutsideClip(element->getBounds(), query Bounds)) {
100 initialState = InitialTriState::kAllOut; 170 initialTriState = InitialTriState::kAllOut;
171 skippable = true;
172 } else if (!embiggens && !element->isAA() &&
173 Element::kRect_Type == element->getType()) {
174 // fIBounds and queryBounds have already acccounted for this element via
175 // clip stack bounds; here we just apply the non-aa roun ding effect.
176 SkIRect nonaaRect;
177 element->getRect().round(&nonaaRect);
178 if (!this->intersectIBounds(nonaaRect)) {
179 return;
180 }
101 skippable = true; 181 skippable = true;
102 } 182 }
103 } 183 }
104 if (!skippable) { 184 if (!skippable) {
105 emsmallens = true; 185 emsmallens = true;
106 } 186 }
107 break; 187 break;
108 case SkRegion::kUnion_Op: 188 case SkRegion::kUnion_Op:
109 // If the union-ed shape contains the entire bounds then after t his element 189 // If the union-ed shape contains the entire bounds then after t his element
110 // the bounds is entirely inside the clip. If the union-ed shape is outside the 190 // the bounds is entirely inside the clip. If the union-ed shape is outside the
111 // bounds then this op can be skipped. 191 // bounds then this op can be skipped.
112 if (element->isInverseFilled()) { 192 if (element->isInverseFilled()) {
113 if (element->contains(relaxedQueryBounds)) { 193 if (element->contains(relaxedQueryBounds)) {
114 skippable = true; 194 skippable = true;
115 } else if (GrClip::IsOutsideClip(element->getBounds(), query Bounds)) { 195 } else if (GrClip::IsOutsideClip(element->getBounds(), query Bounds)) {
116 initialState = InitialTriState::kAllIn; 196 initialTriState = InitialTriState::kAllIn;
117 skippable = true; 197 skippable = true;
118 } 198 }
119 } else { 199 } else {
120 if (element->contains(relaxedQueryBounds)) { 200 if (element->contains(relaxedQueryBounds)) {
121 initialState = InitialTriState::kAllIn; 201 initialTriState = InitialTriState::kAllIn;
122 skippable = true; 202 skippable = true;
123 } else if (GrClip::IsOutsideClip(element->getBounds(), query Bounds)) { 203 } else if (GrClip::IsOutsideClip(element->getBounds(), query Bounds)) {
124 skippable = true; 204 skippable = true;
125 } 205 }
126 } 206 }
127 if (!skippable) { 207 if (!skippable) {
128 embiggens = true; 208 embiggens = true;
129 } 209 }
130 break; 210 break;
131 case SkRegion::kXOR_Op: 211 case SkRegion::kXOR_Op:
(...skipping 18 matching lines...) Expand all
150 emsmallens = embiggens = true; 230 emsmallens = embiggens = true;
151 } 231 }
152 break; 232 break;
153 case SkRegion::kReverseDifference_Op: 233 case SkRegion::kReverseDifference_Op:
154 // When the bounds is entirely within the rev-diff shape then th is behaves like xor 234 // When the bounds is entirely within the rev-diff shape then th is behaves like xor
155 // and reverses every point inside the bounds. If the shape is c ompletely outside 235 // and reverses every point inside the bounds. If the shape is c ompletely outside
156 // the bounds then we know after this element is applied that th e bounds will be 236 // the bounds then we know after this element is applied that th e bounds will be
157 // all outside the current clip.B 237 // all outside the current clip.B
158 if (element->isInverseFilled()) { 238 if (element->isInverseFilled()) {
159 if (element->contains(relaxedQueryBounds)) { 239 if (element->contains(relaxedQueryBounds)) {
160 initialState = InitialTriState::kAllOut; 240 initialTriState = InitialTriState::kAllOut;
161 skippable = true; 241 skippable = true;
162 } else if (GrClip::IsOutsideClip(element->getBounds(), query Bounds)) { 242 } else if (GrClip::IsOutsideClip(element->getBounds(), query Bounds)) {
163 isFlip = true; 243 isFlip = true;
164 } 244 }
165 } else { 245 } else {
166 if (element->contains(relaxedQueryBounds)) { 246 if (element->contains(relaxedQueryBounds)) {
167 isFlip = true; 247 isFlip = true;
168 } else if (GrClip::IsOutsideClip(element->getBounds(), query Bounds)) { 248 } else if (GrClip::IsOutsideClip(element->getBounds(), query Bounds)) {
169 initialState = InitialTriState::kAllOut; 249 initialTriState = InitialTriState::kAllOut;
170 skippable = true; 250 skippable = true;
171 } 251 }
172 } 252 }
173 if (!skippable) { 253 if (!skippable) {
174 emsmallens = embiggens = true; 254 emsmallens = embiggens = true;
175 } 255 }
176 break; 256 break;
177 257
178 case SkRegion::kReplace_Op: 258 case SkRegion::kReplace_Op:
179 // Replace will always terminate our walk. We will either begin the forward walk 259 // Replace will always terminate our walk. We will either begin the forward walk
180 // at the replace op or detect here than the shape is either com pletely inside 260 // at the replace op or detect here than the shape is either com pletely inside
181 // or completely outside the bounds. In this latter case it can be skipped by 261 // or completely outside the bounds. In this latter case it can be skipped by
182 // setting the correct value for initialState. 262 // setting the correct value for initialTriState.
183 if (element->isInverseFilled()) { 263 if (element->isInverseFilled()) {
184 if (element->contains(relaxedQueryBounds)) { 264 if (element->contains(relaxedQueryBounds)) {
185 initialState = InitialTriState::kAllOut; 265 initialTriState = InitialTriState::kAllOut;
186 skippable = true; 266 skippable = true;
187 } else if (GrClip::IsOutsideClip(element->getBounds(), query Bounds)) { 267 } else if (GrClip::IsOutsideClip(element->getBounds(), query Bounds)) {
188 initialState = InitialTriState::kAllIn; 268 initialTriState = InitialTriState::kAllIn;
189 skippable = true; 269 skippable = true;
190 } 270 }
191 } else { 271 } else {
192 if (element->contains(relaxedQueryBounds)) { 272 if (element->contains(relaxedQueryBounds)) {
193 initialState = InitialTriState::kAllIn; 273 initialTriState = InitialTriState::kAllIn;
194 skippable = true; 274 skippable = true;
195 } else if (GrClip::IsOutsideClip(element->getBounds(), query Bounds)) { 275 } else if (GrClip::IsOutsideClip(element->getBounds(), query Bounds)) {
196 initialState = InitialTriState::kAllOut; 276 initialTriState = InitialTriState::kAllOut;
277 skippable = true;
278 } else if (!embiggens && !element->isAA() &&
279 Element::kRect_Type == element->getType()) {
280 // fIBounds and queryBounds have already acccounted for this element via
281 // clip stack bounds; here we just apply the non-aa roun ding effect.
282 SkIRect nonaaRect;
283 element->getRect().round(&nonaaRect);
284 if (!this->intersectIBounds(nonaaRect)) {
285 return;
286 }
287 initialTriState = InitialTriState::kAllIn;
197 skippable = true; 288 skippable = true;
198 } 289 }
199 } 290 }
200 if (!skippable) { 291 if (!skippable) {
201 initialState = InitialTriState::kAllOut; 292 initialTriState = InitialTriState::kAllOut;
202 embiggens = emsmallens = true; 293 embiggens = emsmallens = true;
203 } 294 }
204 break; 295 break;
205 default: 296 default:
206 SkDEBUGFAIL("Unexpected op."); 297 SkDEBUGFAIL("Unexpected op.");
207 break; 298 break;
208 } 299 }
209 if (!skippable) { 300 if (!skippable) {
210 if (0 == result->count()) { 301 if (0 == fElements.count()) {
211 // This will be the last element. Record the stricter genID. 302 // This will be the last element. Record the stricter genID.
212 *resultGenID = element->getGenID(); 303 fElementsGenID = element->getGenID();
213 } 304 }
214 305
215 // if it is a flip, change it to a bounds-filling rect 306 // if it is a flip, change it to a bounds-filling rect
216 if (isFlip) { 307 if (isFlip) {
217 SkASSERT(SkRegion::kXOR_Op == element->getOp() || 308 SkASSERT(SkRegion::kXOR_Op == element->getOp() ||
218 SkRegion::kReverseDifference_Op == element->getOp()); 309 SkRegion::kReverseDifference_Op == element->getOp());
219 result->addToHead(SkRect::Make(clipIBounds), SkRegion::kReverseD ifference_Op, 310 fElements.addToHead(SkRect::Make(fIBounds), SkRegion::kReverseDi fference_Op, false);
220 false);
221 } else { 311 } else {
222 Element* newElement = result->addToHead(*element); 312 Element* newElement = fElements.addToHead(*element);
223 if (newElement->isAA()) { 313 if (newElement->isAA()) {
224 ++numAAElements; 314 ++numAAElements;
225 } 315 }
226 // Intersecting an inverse shape is the same as differencing the non-inverse shape. 316 // Intersecting an inverse shape is the same as differencing the non-inverse shape.
227 // Replacing with an inverse shape is the same as setting initia lState=kAllIn and 317 // Replacing with an inverse shape is the same as setting initia lState=kAllIn and
228 // differencing the non-inverse shape. 318 // differencing the non-inverse shape.
229 bool isReplace = SkRegion::kReplace_Op == newElement->getOp(); 319 bool isReplace = SkRegion::kReplace_Op == newElement->getOp();
230 if (newElement->isInverseFilled() && 320 if (newElement->isInverseFilled() &&
231 (SkRegion::kIntersect_Op == newElement->getOp() || isReplace )) { 321 (SkRegion::kIntersect_Op == newElement->getOp() || isReplace )) {
232 newElement->invertShapeFillType(); 322 newElement->invertShapeFillType();
233 newElement->setOp(SkRegion::kDifference_Op); 323 newElement->setOp(SkRegion::kDifference_Op);
234 if (isReplace) { 324 if (isReplace) {
235 SkASSERT(InitialTriState::kAllOut == initialState); 325 SkASSERT(InitialTriState::kAllOut == initialTriState);
236 initialState = InitialTriState::kAllIn; 326 initialTriState = InitialTriState::kAllIn;
237 } 327 }
238 } 328 }
239 } 329 }
240 } 330 }
241 } 331 }
242 332
243 if ((InitialTriState::kAllOut == initialState && !embiggens) || 333 if ((InitialTriState::kAllOut == initialTriState && !embiggens) ||
244 (InitialTriState::kAllIn == initialState && !emsmallens)) { 334 (InitialTriState::kAllIn == initialTriState && !emsmallens)) {
245 result->reset(); 335 fElements.reset();
246 numAAElements = 0; 336 numAAElements = 0;
247 } else { 337 } else {
248 Element* element = result->headIter().get(); 338 Element* element = fElements.headIter().get();
249 while (element) { 339 while (element) {
250 bool skippable = false; 340 bool skippable = false;
251 switch (element->getOp()) { 341 switch (element->getOp()) {
252 case SkRegion::kDifference_Op: 342 case SkRegion::kDifference_Op:
253 // subtracting from the empty set yields the empty set. 343 // subtracting from the empty set yields the empty set.
254 skippable = InitialTriState::kAllOut == initialState; 344 skippable = InitialTriState::kAllOut == initialTriState;
255 break; 345 break;
256 case SkRegion::kIntersect_Op: 346 case SkRegion::kIntersect_Op:
257 // intersecting with the empty set yields the empty set 347 // intersecting with the empty set yields the empty set
258 if (InitialTriState::kAllOut == initialState) { 348 if (InitialTriState::kAllOut == initialTriState) {
259 skippable = true; 349 skippable = true;
260 } else { 350 } else {
261 // We can clear to zero and then simply draw the clip el ement. 351 // We can clear to zero and then simply draw the clip el ement.
262 initialState = InitialTriState::kAllOut; 352 initialTriState = InitialTriState::kAllOut;
263 element->setOp(SkRegion::kReplace_Op); 353 element->setOp(SkRegion::kReplace_Op);
264 } 354 }
265 break; 355 break;
266 case SkRegion::kUnion_Op: 356 case SkRegion::kUnion_Op:
267 if (InitialTriState::kAllIn == initialState) { 357 if (InitialTriState::kAllIn == initialTriState) {
268 // unioning the infinite plane with anything is a no-op. 358 // unioning the infinite plane with anything is a no-op.
269 skippable = true; 359 skippable = true;
270 } else { 360 } else {
271 // unioning the empty set with a shape is the shape. 361 // unioning the empty set with a shape is the shape.
272 element->setOp(SkRegion::kReplace_Op); 362 element->setOp(SkRegion::kReplace_Op);
273 } 363 }
274 break; 364 break;
275 case SkRegion::kXOR_Op: 365 case SkRegion::kXOR_Op:
276 if (InitialTriState::kAllOut == initialState) { 366 if (InitialTriState::kAllOut == initialTriState) {
277 // xor could be changed to diff in the kAllIn case, not sure it's a win. 367 // xor could be changed to diff in the kAllIn case, not sure it's a win.
278 element->setOp(SkRegion::kReplace_Op); 368 element->setOp(SkRegion::kReplace_Op);
279 } 369 }
280 break; 370 break;
281 case SkRegion::kReverseDifference_Op: 371 case SkRegion::kReverseDifference_Op:
282 if (InitialTriState::kAllIn == initialState) { 372 if (InitialTriState::kAllIn == initialTriState) {
283 // subtracting the whole plane will yield the empty set. 373 // subtracting the whole plane will yield the empty set.
284 skippable = true; 374 skippable = true;
285 initialState = InitialTriState::kAllOut; 375 initialTriState = InitialTriState::kAllOut;
286 } else { 376 } else {
287 // this picks up flips inserted in the backwards pass. 377 // this picks up flips inserted in the backwards pass.
288 skippable = element->isInverseFilled() ? 378 skippable = element->isInverseFilled() ?
289 GrClip::IsOutsideClip(element->getBounds(), queryBou nds) : 379 GrClip::IsOutsideClip(element->getBounds(), queryBou nds) :
290 element->contains(relaxedQueryBounds); 380 element->contains(relaxedQueryBounds);
291 if (skippable) { 381 if (skippable) {
292 initialState = InitialTriState::kAllIn; 382 initialTriState = InitialTriState::kAllIn;
293 } else { 383 } else {
294 element->setOp(SkRegion::kReplace_Op); 384 element->setOp(SkRegion::kReplace_Op);
295 } 385 }
296 } 386 }
297 break; 387 break;
298 case SkRegion::kReplace_Op: 388 case SkRegion::kReplace_Op:
299 skippable = false; // we would have skipped it in the backwa rds walk if we 389 skippable = false; // we would have skipped it in the backwa rds walk if we
300 // could've. 390 // could've.
301 break; 391 break;
302 default: 392 default:
303 SkDEBUGFAIL("Unexpected op."); 393 SkDEBUGFAIL("Unexpected op.");
304 break; 394 break;
305 } 395 }
306 if (!skippable) { 396 if (!skippable) {
307 break; 397 break;
308 } else { 398 } else {
309 if (element->isAA()) { 399 if (element->isAA()) {
310 --numAAElements; 400 --numAAElements;
311 } 401 }
312 result->popHead(); 402 fElements.popHead();
313 element = result->headIter().get(); 403 element = fElements.headIter().get();
314 } 404 }
315 } 405 }
316 } 406 }
317 *requiresAA = numAAElements > 0; 407 fRequiresAA = numAAElements > 0;
318 408
319 SkASSERT(InitialTriState::kUnknown != initialState); 409 SkASSERT(InitialTriState::kUnknown != initialTriState);
320 return static_cast<GrReducedClip::InitialState>(initialState); 410 fInitialState = static_cast<GrReducedClip::InitialState>(initialTriState);
321 } 411 }
322 412
323 /* 413 inline bool GrReducedClip::intersectIBounds(const SkIRect& irect) {
324 There are plenty of optimizations that could be added here. Maybe flips could be folded into 414 SkASSERT(fHasIBounds);
325 earlier operations. Or would inserting flips and reversing earlier ops ever be a win? Perhaps 415 if (!fIBounds.intersect(irect)) {
326 for the case where the bounds are kInsideOut_BoundsType. We could restrict earli er operations 416 fHasIBounds = false;
327 based on later intersect operations, and perhaps remove intersect-rects. We coul d optionally 417 fElements.reset();
328 take a rect in case the caller knows a bound on what is to be drawn through this clip. 418 fRequiresAA = false;
329 */ 419 fInitialState = InitialState::kAllOut;
330 GrReducedClip::GrReducedClip(const SkClipStack& stack, const SkRect& queryBounds ) { 420 return false;
331 SkASSERT(!queryBounds.isEmpty());
332 fHasIBounds = false;
333
334 if (stack.isWideOpen()) {
335 fInitialState = InitialState::kAllIn;
336 return;
337 } 421 }
338 422 return true;
339 SkClipStack::BoundsType stackBoundsType;
340 SkRect stackBounds;
341 bool iior;
342 stack.getBounds(&stackBounds, &stackBoundsType, &iior);
343
344 if (stackBounds.isEmpty() || GrClip::IsOutsideClip(stackBounds, queryBounds) ) {
345 bool insideOut = SkClipStack::kInsideOut_BoundsType == stackBoundsType;
346 fInitialState = insideOut ? InitialState::kAllIn : InitialState::kAllOut ;
347 return;
348 }
349
350 if (iior) {
351 // "Is intersection of rects" means the clip is a single rect indicated by the stack bounds.
352 // This should only be true if aa/non-aa status matches among all elemen ts.
353 SkASSERT(SkClipStack::kNormal_BoundsType == stackBoundsType);
354 SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
355 if (!iter.prev()->isAA() || GrClip::IsPixelAligned(stackBounds)) {
356 // The clip is a non-aa rect. This is the one spot where we can actu ally implement the
357 // clip (using fIBounds) rather than just telling the caller what it should be.
358 stackBounds.round(&fIBounds);
359 fHasIBounds = true;
360 fInitialState = fIBounds.isEmpty() ? InitialState::kAllOut : Initial State::kAllIn;
361 return;
362 }
363 if (GrClip::IsInsideClip(stackBounds, queryBounds)) {
364 fInitialState = InitialState::kAllIn;
365 return;
366 }
367
368 SkRect tightBounds;
369 SkAssertResult(tightBounds.intersect(stackBounds, queryBounds));
370 fIBounds = GrClip::GetPixelIBounds(tightBounds);
371 SkASSERT(!fIBounds.isEmpty()); // Empty should have been blocked by IsOu tsideClip above.
372 fHasIBounds = true;
373
374 // Implement the clip with an AA rect element.
375 fElements.addToHead(stackBounds, SkRegion::kReplace_Op, true/*doAA*/);
376 fElementsGenID = stack.getTopmostGenID();
377 fRequiresAA = true;
378
379 fInitialState = InitialState::kAllOut;
380 return;
381 }
382
383 SkRect tighterQuery = queryBounds;
384 if (SkClipStack::kNormal_BoundsType == stackBoundsType) {
385 // Tighten the query by introducing a new clip at the stack's pixel boun daries. (This new
386 // clip will be enforced by the scissor through fIBounds.)
387 SkAssertResult(tighterQuery.intersect(GrClip::GetPixelBounds(stackBounds )));
388 }
389
390 fIBounds = GrClip::GetPixelIBounds(tighterQuery);
391 SkASSERT(!fIBounds.isEmpty()); // Empty should have been blocked by IsOutsid eClip above.
392 fHasIBounds = true;
393
394 // Now that we have determined the bounds to use and filtered out the trivia l cases, call the
395 // helper that actually walks the stack.
396 fInitialState = reduced_stack_walker(stack, tighterQuery, fIBounds, &fElemen ts, &fElementsGenID,
397 &fRequiresAA);
398 } 423 }
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