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