OLD | NEW |
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2012 Google Inc. | 3 * Copyright 2012 Google Inc. |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 | 8 |
9 #include "GrClipMaskManager.h" | 9 #include "GrClipMaskManager.h" |
10 #include "GrAAConvexPathRenderer.h" | 10 #include "GrAAConvexPathRenderer.h" |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
103 return true; | 103 return true; |
104 } | 104 } |
105 } | 105 } |
106 } | 106 } |
107 return false; | 107 return false; |
108 } | 108 } |
109 | 109 |
110 bool GrClipMaskManager::installClipEffects(const ElementList& elements, | 110 bool GrClipMaskManager::installClipEffects(const ElementList& elements, |
111 GrDrawState::AutoRestoreEffects* are, | 111 GrDrawState::AutoRestoreEffects* are, |
112 const SkVector& clipToRTOffset, | 112 const SkVector& clipToRTOffset, |
113 const SkRect* drawBounds) { | 113 const SkRect* drawBounds, |
| 114 SkIRect* scissorRect) { |
| 115 |
| 116 SkASSERT(NULL != scissorRect); |
114 | 117 |
115 GrDrawState* drawState = fGpu->drawState(); | 118 GrDrawState* drawState = fGpu->drawState(); |
116 SkRect boundsInClipSpace; | 119 SkRect boundsInClipSpace; |
117 if (NULL != drawBounds) { | 120 if (NULL != drawBounds) { |
118 boundsInClipSpace = *drawBounds; | 121 boundsInClipSpace = *drawBounds; |
119 boundsInClipSpace.offset(-clipToRTOffset.fX, -clipToRTOffset.fY); | 122 boundsInClipSpace.offset(-clipToRTOffset.fX, -clipToRTOffset.fY); |
120 } | 123 } |
121 | 124 |
122 are->set(drawState); | 125 are->set(drawState); |
123 GrRenderTarget* rt = drawState->getRenderTarget(); | 126 GrRenderTarget* rt = drawState->getRenderTarget(); |
124 ElementList::Iter iter(elements); | 127 // We iterate from the top of the stack to the bottom. We do this because we
select the first |
| 128 // BW rectangle as the scissor. Clients performing hierarchical rendering te
nd to use smaller |
| 129 // clips towards the top of the clip stack. Smaller scissor rects can help t
iled architectures |
| 130 // skip processing tiles for draws. |
| 131 ElementList::Iter iter(elements, ElementList::Iter::kTail_IterStart); |
125 | 132 |
126 bool setARE = false; | 133 bool setARE = false; |
127 bool failed = false; | 134 bool failed = false; |
128 | 135 |
129 while (NULL != iter.get()) { | 136 while (NULL != iter.get()) { |
130 SkRegion::Op op = iter.get()->getOp(); | 137 SkRegion::Op op = iter.get()->getOp(); |
131 bool invert; | 138 bool invert; |
132 bool skip = false; | 139 bool skip = false; |
133 switch (op) { | 140 switch (op) { |
134 case SkRegion::kReplace_Op: | 141 case SkRegion::kReplace_Op: |
(...skipping 15 matching lines...) Expand all Loading... |
150 break; | 157 break; |
151 } | 158 } |
152 if (failed) { | 159 if (failed) { |
153 break; | 160 break; |
154 } | 161 } |
155 | 162 |
156 if (!skip) { | 163 if (!skip) { |
157 GrEffectEdgeType edgeType; | 164 GrEffectEdgeType edgeType; |
158 if (GR_AA_CLIP && iter.get()->isAA()) { | 165 if (GR_AA_CLIP && iter.get()->isAA()) { |
159 if (rt->isMultisampled()) { | 166 if (rt->isMultisampled()) { |
160 // Coverage based AA clips don't place nicely with MSAA. | 167 // Coverage based AA clips don't play nicely with MSAA. |
161 failed = true; | 168 failed = true; |
162 break; | 169 break; |
163 } | 170 } |
164 edgeType = invert ? kInverseFillAA_GrEffectEdgeType : kFillAA_Gr
EffectEdgeType; | 171 edgeType = invert ? kInverseFillAA_GrEffectEdgeType : kFillAA_Gr
EffectEdgeType; |
165 } else { | 172 } else { |
166 edgeType = invert ? kInverseFillBW_GrEffectEdgeType : kFillBW_Gr
EffectEdgeType; | 173 edgeType = invert ? kInverseFillBW_GrEffectEdgeType : kFillBW_Gr
EffectEdgeType; |
167 } | 174 } |
| 175 // We don't want to exit if we convert a BW rect clip to a scissor. |
| 176 bool failIfNoEffect = true; |
168 SkAutoTUnref<GrEffectRef> effect; | 177 SkAutoTUnref<GrEffectRef> effect; |
169 switch (iter.get()->getType()) { | 178 switch (iter.get()->getType()) { |
170 case SkClipStack::Element::kPath_Type: | 179 case SkClipStack::Element::kPath_Type: |
171 effect.reset(GrConvexPolyEffect::Create(edgeType, iter.get()
->getPath(), | 180 effect.reset(GrConvexPolyEffect::Create(edgeType, iter.get()
->getPath(), |
172 &clipToRTOffset)); | 181 &clipToRTOffset)); |
173 break; | 182 break; |
174 case SkClipStack::Element::kRRect_Type: { | 183 case SkClipStack::Element::kRRect_Type: { |
175 SkRRect rrect = iter.get()->getRRect(); | 184 SkRRect rrect = iter.get()->getRRect(); |
176 rrect.offset(clipToRTOffset.fX, clipToRTOffset.fY); | 185 rrect.offset(clipToRTOffset.fX, clipToRTOffset.fY); |
177 effect.reset(GrRRectEffect::Create(edgeType, rrect)); | 186 effect.reset(GrRRectEffect::Create(edgeType, rrect)); |
178 break; | 187 break; |
179 } | 188 } |
180 case SkClipStack::Element::kRect_Type: { | 189 case SkClipStack::Element::kRect_Type: { |
181 SkRect rect = iter.get()->getRect(); | 190 SkRect rect = iter.get()->getRect(); |
182 rect.offset(clipToRTOffset.fX, clipToRTOffset.fY); | 191 rect.offset(clipToRTOffset.fX, clipToRTOffset.fY); |
183 effect.reset(GrConvexPolyEffect::Create(edgeType, rect)); | 192 if (kFillBW_GrEffectEdgeType == edgeType && scissorRect->isE
mpty()) { |
| 193 // This is OK because we only allow clip operations that
shrink the clip |
| 194 // to be implemented as effects. |
| 195 rect.roundOut(scissorRect); |
| 196 failIfNoEffect = false; |
| 197 } else { |
| 198 effect.reset(GrConvexPolyEffect::Create(edgeType, rect))
; |
| 199 } |
184 break; | 200 break; |
185 } | 201 } |
186 default: | 202 default: |
187 break; | 203 break; |
188 } | 204 } |
189 if (effect) { | 205 if (effect) { |
190 if (!setARE) { | 206 if (!setARE) { |
191 are->set(fGpu->drawState()); | 207 are->set(fGpu->drawState()); |
192 setARE = true; | 208 setARE = true; |
193 } | 209 } |
194 fGpu->drawState()->addCoverageEffect(effect); | 210 fGpu->drawState()->addCoverageEffect(effect); |
195 } else { | 211 } else if (failIfNoEffect) { |
196 failed = true; | 212 failed = true; |
197 break; | 213 break; |
198 } | 214 } |
199 } | 215 } |
200 iter.next(); | 216 iter.prev(); |
201 } | 217 } |
202 | 218 |
203 if (failed) { | 219 if (failed) { |
204 are->set(NULL); | 220 are->set(NULL); |
205 } | 221 } |
206 | 222 |
207 return !failed; | 223 return !failed; |
208 } | 224 } |
209 | 225 |
| 226 static inline bool rect_contains_irect(const SkIRect ir, const SkRect& r) { |
| 227 SkASSERT(!ir.isEmpty()); |
| 228 return ir.fLeft <= r.fLeft && ir.fTop <= r.fTop && |
| 229 ir.fRight >= r.fRight && ir.fBottom >= r.fBottom; |
| 230 } |
| 231 |
210 //////////////////////////////////////////////////////////////////////////////// | 232 //////////////////////////////////////////////////////////////////////////////// |
211 // sort out what kind of clip mask needs to be created: alpha, stencil, | 233 // sort out what kind of clip mask needs to be created: alpha, stencil, |
212 // scissor, or entirely software | 234 // scissor, or entirely software |
213 bool GrClipMaskManager::setupClipping(const GrClipData* clipDataIn, | 235 bool GrClipMaskManager::setupClipping(const GrClipData* clipDataIn, |
214 GrDrawState::AutoRestoreEffects* are, | 236 GrDrawState::AutoRestoreEffects* are, |
215 const SkRect* devBounds) { | 237 const SkRect* devBounds) { |
216 fCurrClipMaskType = kNone_ClipMaskType; | 238 fCurrClipMaskType = kNone_ClipMaskType; |
217 | 239 |
218 ElementList elements(16); | 240 ElementList elements(16); |
219 int32_t genID; | 241 int32_t genID; |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
256 | 278 |
257 // An element count of 4 was chosen because of the common pattern in Blink o
f: | 279 // An element count of 4 was chosen because of the common pattern in Blink o
f: |
258 // isect RR | 280 // isect RR |
259 // diff RR | 281 // diff RR |
260 // isect convex_poly | 282 // isect convex_poly |
261 // isect convex_poly | 283 // isect convex_poly |
262 // when drawing rounded div borders. This could probably be tuned based on a | 284 // when drawing rounded div borders. This could probably be tuned based on a |
263 // configuration's relative costs of switching RTs to generate a mask vs | 285 // configuration's relative costs of switching RTs to generate a mask vs |
264 // longer shaders. | 286 // longer shaders. |
265 if (elements.count() <= 4) { | 287 if (elements.count() <= 4) { |
| 288 SkIRect scissorRect; |
| 289 scissorRect.setEmpty(); |
266 SkVector clipToRTOffset = { SkIntToScalar(-clipDataIn->fOrigin.fX), | 290 SkVector clipToRTOffset = { SkIntToScalar(-clipDataIn->fOrigin.fX), |
267 SkIntToScalar(-clipDataIn->fOrigin.fY) }; | 291 SkIntToScalar(-clipDataIn->fOrigin.fY) }; |
268 if (elements.isEmpty() || | 292 if (elements.isEmpty() || |
269 (requiresAA && this->installClipEffects(elements, are, clipToRTOffse
t, devBounds))) { | 293 this->installClipEffects(elements, are, clipToRTOffset, devBounds, &
scissorRect)) { |
270 SkIRect scissorSpaceIBounds(clipSpaceIBounds); | 294 if (scissorRect.isEmpty()) { |
271 scissorSpaceIBounds.offset(-clipDataIn->fOrigin); | 295 // We may still want to use a scissor, especially on tiled archi
tectures. |
272 if (NULL == devBounds || | 296 scissorRect = clipSpaceIBounds; |
273 !SkRect::Make(scissorSpaceIBounds).contains(*devBounds)) { | 297 scissorRect.offset(-clipDataIn->fOrigin); |
274 fGpu->enableScissor(scissorSpaceIBounds); | 298 if (NULL == devBounds || |
| 299 !rect_contains_irect(scissorRect, *devBounds)) { |
| 300 fGpu->enableScissor(scissorRect); |
| 301 } else { |
| 302 // When the vertices that will be rendered fit fully inside
the clip's bounds |
| 303 // then providing the scissor rect will not help the driver
eliminate tiles |
| 304 // from consideration for the draw, but changing the scissor
will cause |
| 305 // state changes between draws. |
| 306 fGpu->disableScissor(); |
| 307 } |
275 } else { | 308 } else { |
276 fGpu->disableScissor(); | 309 scissorRect.fLeft = SkTMax(0, scissorRect.fLeft); |
| 310 scissorRect.fTop = SkTMax(0, scissorRect.fTop); |
| 311 scissorRect.fRight = SkTMin(rt->width(), scissorRect.fRight); |
| 312 scissorRect.fBottom = SkTMin(rt->height(), scissorRect.fBottom); |
| 313 fGpu->enableScissor(scissorRect); |
277 } | 314 } |
278 this->setGpuStencil(); | 315 this->setGpuStencil(); |
279 return true; | 316 return true; |
280 } | 317 } |
281 } | 318 } |
282 | 319 |
283 #if GR_AA_CLIP | 320 #if GR_AA_CLIP |
284 // If MSAA is enabled we can do everything in the stencil buffer. | 321 // If MSAA is enabled we can do everything in the stencil buffer. |
285 if (0 == rt->numSamples() && requiresAA) { | 322 if (0 == rt->numSamples() && requiresAA) { |
286 GrTexture* result = NULL; | 323 GrTexture* result = NULL; |
(...skipping 852 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1139 | 1176 |
1140 // TODO: dynamically attach a stencil buffer | 1177 // TODO: dynamically attach a stencil buffer |
1141 int stencilBits = 0; | 1178 int stencilBits = 0; |
1142 GrStencilBuffer* stencilBuffer = | 1179 GrStencilBuffer* stencilBuffer = |
1143 drawState.getRenderTarget()->getStencilBuffer(); | 1180 drawState.getRenderTarget()->getStencilBuffer(); |
1144 if (NULL != stencilBuffer) { | 1181 if (NULL != stencilBuffer) { |
1145 stencilBits = stencilBuffer->bits(); | 1182 stencilBits = stencilBuffer->bits(); |
1146 this->adjustStencilParams(settings, clipMode, stencilBits); | 1183 this->adjustStencilParams(settings, clipMode, stencilBits); |
1147 } | 1184 } |
1148 } | 1185 } |
OLD | NEW |