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

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

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

Powered by Google App Engine
This is Rietveld 408576698