| OLD | NEW |
| 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 "GrClipMaskManager.h" | 8 #include "GrClipMaskManager.h" |
| 10 #include "GrAAConvexPathRenderer.h" | 9 #include "GrAAConvexPathRenderer.h" |
| 11 #include "GrAAHairLinePathRenderer.h" | 10 #include "GrAAHairLinePathRenderer.h" |
| 12 #include "GrAARectRenderer.h" | 11 #include "GrAARectRenderer.h" |
| 13 #include "GrDrawTargetCaps.h" | 12 #include "GrDrawTargetCaps.h" |
| 14 #include "GrPaint.h" | 13 #include "GrPaint.h" |
| 15 #include "GrPathRenderer.h" | 14 #include "GrPathRenderer.h" |
| 16 #include "GrRenderTarget.h" | 15 #include "GrRenderTarget.h" |
| 17 #include "GrStencilBuffer.h" | 16 #include "GrStencilBuffer.h" |
| 18 #include "GrSWMaskHelper.h" | 17 #include "GrSWMaskHelper.h" |
| 19 #include "SkRasterClip.h" | 18 #include "SkRasterClip.h" |
| 20 #include "SkStrokeRec.h" | 19 #include "SkStrokeRec.h" |
| 21 #include "SkTLazy.h" | 20 #include "SkTLazy.h" |
| 22 #include "effects/GrTextureDomain.h" | 21 #include "effects/GrTextureDomain.h" |
| 23 #include "effects/GrConvexPolyEffect.h" | 22 #include "effects/GrConvexPolyEffect.h" |
| 24 #include "effects/GrRRectEffect.h" | 23 #include "effects/GrRRectEffect.h" |
| 25 | 24 |
| 26 #define GR_AA_CLIP 1 | 25 #define GR_AA_CLIP 1 |
| 27 | |
| 28 typedef SkClipStack::Element Element; | 26 typedef SkClipStack::Element Element; |
| 29 | 27 |
| 30 //////////////////////////////////////////////////////////////////////////////// | 28 //////////////////////////////////////////////////////////////////////////////// |
| 31 namespace { | 29 namespace { |
| 32 // set up the draw state to enable the aa clipping mask. Besides setting up the | 30 // set up the draw state to enable the aa clipping mask. Besides setting up the |
| 33 // stage matrix this also alters the vertex layout | 31 // stage matrix this also alters the vertex layout |
| 34 void setup_drawstate_aaclip(GrDrawTarget* gpu, | 32 void setup_drawstate_aaclip(const SkIRect &devBound, |
| 35 GrTexture* result, | 33 GrDrawState* drawState, |
| 36 const SkIRect &devBound) { | 34 GrTexture* result) { |
| 37 GrDrawState* drawState = gpu->drawState(); | |
| 38 SkASSERT(drawState); | 35 SkASSERT(drawState); |
| 39 | 36 |
| 40 SkMatrix mat; | 37 SkMatrix mat; |
| 41 // We want to use device coords to compute the texture coordinates. We set o
ur matrix to be | 38 // We want to use device coords to compute the texture coordinates. We set o
ur matrix to be |
| 42 // equal to the view matrix followed by an offset to the devBound, and then
a scaling matrix to | 39 // equal to the view matrix followed by an offset to the devBound, and then
a scaling matrix to |
| 43 // normalized coords. We apply this matrix to the vertex positions rather th
an local coords. | 40 // normalized coords. We apply this matrix to the vertex positions rather th
an local coords. |
| 44 mat.setIDiv(result->width(), result->height()); | 41 mat.setIDiv(result->width(), result->height()); |
| 45 mat.preTranslate(SkIntToScalar(-devBound.fLeft), | 42 mat.preTranslate(SkIntToScalar(-devBound.fLeft), |
| 46 SkIntToScalar(-devBound.fTop)); | 43 SkIntToScalar(-devBound.fTop)); |
| 47 mat.preConcat(drawState->getViewMatrix()); | 44 mat.preConcat(drawState->getViewMatrix()); |
| 48 | 45 |
| 49 SkIRect domainTexels = SkIRect::MakeWH(devBound.width(), devBound.height()); | 46 SkIRect domainTexels = SkIRect::MakeWH(devBound.width(), devBound.height()); |
| 50 // This could be a long-lived effect that is cached with the alpha-mask. | 47 // This could be a long-lived effect that is cached with the alpha-mask. |
| 51 drawState->addCoverageProcessor( | 48 drawState->addCoverageProcessor( |
| 52 GrTextureDomainEffect::Create(result, | 49 GrTextureDomainEffect::Create(result, |
| 53 mat, | 50 mat, |
| 54 GrTextureDomain::MakeTexelDomain(result, d
omainTexels), | 51 GrTextureDomain::MakeTexelDomain(result, d
omainTexels), |
| 55 GrTextureDomain::kDecal_Mode, | 52 GrTextureDomain::kDecal_Mode, |
| 56 GrTextureParams::kNone_FilterMode, | 53 GrTextureParams::kNone_FilterMode, |
| 57 kPosition_GrCoordSet))->unref(); | 54 kPosition_GrCoordSet))->unref(); |
| 58 } | 55 } |
| 59 | 56 |
| 60 bool path_needs_SW_renderer(GrContext* context, | 57 bool path_needs_SW_renderer(GrContext* context, |
| 61 GrDrawTarget* gpu, | 58 const GrDrawTarget* gpu, |
| 59 const GrDrawState* drawState, |
| 62 const SkPath& origPath, | 60 const SkPath& origPath, |
| 63 const SkStrokeRec& stroke, | 61 const SkStrokeRec& stroke, |
| 64 bool doAA) { | 62 bool doAA) { |
| 65 // the gpu alpha mask will draw the inverse paths as non-inverse to a temp b
uffer | 63 // the gpu alpha mask will draw the inverse paths as non-inverse to a temp b
uffer |
| 66 SkTCopyOnFirstWrite<SkPath> path(origPath); | 64 SkTCopyOnFirstWrite<SkPath> path(origPath); |
| 67 if (path->isInverseFillType()) { | 65 if (path->isInverseFillType()) { |
| 68 path.writable()->toggleInverseFillType(); | 66 path.writable()->toggleInverseFillType(); |
| 69 } | 67 } |
| 70 // last (false) parameter disallows use of the SW path renderer | 68 // last (false) parameter disallows use of the SW path renderer |
| 71 GrPathRendererChain::DrawType type = doAA ? | 69 GrPathRendererChain::DrawType type = doAA ? |
| 72 GrPathRendererChain::kColorAntiAlias_Dr
awType : | 70 GrPathRendererChain::kColorAntiAlias_Dr
awType : |
| 73 GrPathRendererChain::kColor_DrawType; | 71 GrPathRendererChain::kColor_DrawType; |
| 74 | 72 |
| 75 return NULL == context->getPathRenderer(*path, stroke, gpu, false, type); | 73 return NULL == context->getPathRenderer(gpu, drawState, *path, stroke, false
, type); |
| 76 } | 74 } |
| 77 | |
| 78 } | 75 } |
| 79 | 76 |
| 80 /* | 77 /* |
| 81 * This method traverses the clip stack to see if the GrSoftwarePathRenderer | 78 * This method traverses the clip stack to see if the GrSoftwarePathRenderer |
| 82 * will be used on any element. If so, it returns true to indicate that the | 79 * will be used on any element. If so, it returns true to indicate that the |
| 83 * entire clip should be rendered in SW and then uploaded en masse to the gpu. | 80 * entire clip should be rendered in SW and then uploaded en masse to the gpu. |
| 84 */ | 81 */ |
| 85 bool GrClipMaskManager::useSWOnlyPath(const GrReducedClip::ElementList& elements
) { | 82 bool GrClipMaskManager::useSWOnlyPath(const GrDrawState* drawState, |
| 86 | 83 const GrReducedClip::ElementList& elements
) { |
| 87 // TODO: generalize this function so that when | 84 // TODO: generalize this function so that when |
| 88 // a clip gets complex enough it can just be done in SW regardless | 85 // a clip gets complex enough it can just be done in SW regardless |
| 89 // of whether it would invoke the GrSoftwarePathRenderer. | 86 // of whether it would invoke the GrSoftwarePathRenderer. |
| 90 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); | 87 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); |
| 91 | 88 |
| 92 for (GrReducedClip::ElementList::Iter iter(elements.headIter()); iter.get();
iter.next()) { | 89 for (GrReducedClip::ElementList::Iter iter(elements.headIter()); iter.get();
iter.next()) { |
| 93 const Element* element = iter.get(); | 90 const Element* element = iter.get(); |
| 94 // rects can always be drawn directly w/o using the software path | 91 // rects can always be drawn directly w/o using the software path |
| 95 // Skip rrects once we're drawing them directly. | 92 // Skip rrects once we're drawing them directly. |
| 96 if (Element::kRect_Type != element->getType()) { | 93 if (Element::kRect_Type != element->getType()) { |
| 97 SkPath path; | 94 SkPath path; |
| 98 element->asPath(&path); | 95 element->asPath(&path); |
| 99 if (path_needs_SW_renderer(this->getContext(), fClipTarget, path, st
roke, | 96 if (path_needs_SW_renderer(this->getContext(), fClipTarget, drawStat
e, path, stroke, |
| 100 element->isAA())) { | 97 element->isAA())) { |
| 101 return true; | 98 return true; |
| 102 } | 99 } |
| 103 } | 100 } |
| 104 } | 101 } |
| 105 return false; | 102 return false; |
| 106 } | 103 } |
| 107 | 104 |
| 108 bool GrClipMaskManager::installClipEffects(const GrReducedClip::ElementList& ele
ments, | 105 bool GrClipMaskManager::installClipEffects(GrDrawState* drawState, |
| 109 GrDrawState::AutoRestoreEffects* are, | 106 GrDrawState::AutoRestoreEffects* are, |
| 107 const GrReducedClip::ElementList& ele
ments, |
| 110 const SkVector& clipToRTOffset, | 108 const SkVector& clipToRTOffset, |
| 111 const SkRect* drawBounds) { | 109 const SkRect* drawBounds) { |
| 112 | |
| 113 GrDrawState* drawState = fClipTarget->drawState(); | |
| 114 SkRect boundsInClipSpace; | 110 SkRect boundsInClipSpace; |
| 115 if (drawBounds) { | 111 if (drawBounds) { |
| 116 boundsInClipSpace = *drawBounds; | 112 boundsInClipSpace = *drawBounds; |
| 117 boundsInClipSpace.offset(-clipToRTOffset.fX, -clipToRTOffset.fY); | 113 boundsInClipSpace.offset(-clipToRTOffset.fX, -clipToRTOffset.fY); |
| 118 } | 114 } |
| 119 | 115 |
| 120 are->set(drawState); | 116 are->set(drawState); |
| 121 GrRenderTarget* rt = drawState->getRenderTarget(); | 117 GrRenderTarget* rt = drawState->getRenderTarget(); |
| 122 GrReducedClip::ElementList::Iter iter(elements); | 118 GrReducedClip::ElementList::Iter iter(elements); |
| 123 | |
| 124 bool setARE = false; | |
| 125 bool failed = false; | 119 bool failed = false; |
| 126 | |
| 127 while (iter.get()) { | 120 while (iter.get()) { |
| 128 SkRegion::Op op = iter.get()->getOp(); | 121 SkRegion::Op op = iter.get()->getOp(); |
| 129 bool invert; | 122 bool invert; |
| 130 bool skip = false; | 123 bool skip = false; |
| 131 switch (op) { | 124 switch (op) { |
| 132 case SkRegion::kReplace_Op: | 125 case SkRegion::kReplace_Op: |
| 133 SkASSERT(iter.get() == elements.head()); | 126 SkASSERT(iter.get() == elements.head()); |
| 134 // Fallthrough, handled same as intersect. | 127 // Fallthrough, handled same as intersect. |
| 135 case SkRegion::kIntersect_Op: | 128 case SkRegion::kIntersect_Op: |
| 136 invert = false; | 129 invert = false; |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 180 case SkClipStack::Element::kRect_Type: { | 173 case SkClipStack::Element::kRect_Type: { |
| 181 SkRect rect = iter.get()->getRect(); | 174 SkRect rect = iter.get()->getRect(); |
| 182 rect.offset(clipToRTOffset.fX, clipToRTOffset.fY); | 175 rect.offset(clipToRTOffset.fX, clipToRTOffset.fY); |
| 183 fp.reset(GrConvexPolyEffect::Create(edgeType, rect)); | 176 fp.reset(GrConvexPolyEffect::Create(edgeType, rect)); |
| 184 break; | 177 break; |
| 185 } | 178 } |
| 186 default: | 179 default: |
| 187 break; | 180 break; |
| 188 } | 181 } |
| 189 if (fp) { | 182 if (fp) { |
| 190 if (!setARE) { | 183 drawState->addCoverageProcessor(fp); |
| 191 are->set(fClipTarget->drawState()); | |
| 192 setARE = true; | |
| 193 } | |
| 194 fClipTarget->drawState()->addCoverageProcessor(fp); | |
| 195 } else { | 184 } else { |
| 196 failed = true; | 185 failed = true; |
| 197 break; | 186 break; |
| 198 } | 187 } |
| 199 } | 188 } |
| 200 iter.next(); | 189 iter.next(); |
| 201 } | 190 } |
| 202 | 191 |
| 203 if (failed) { | 192 if (failed) { |
| 204 are->set(NULL); | 193 are->set(NULL); |
| 205 } | 194 } |
| 206 | |
| 207 return !failed; | 195 return !failed; |
| 208 } | 196 } |
| 209 | 197 |
| 210 //////////////////////////////////////////////////////////////////////////////// | 198 //////////////////////////////////////////////////////////////////////////////// |
| 211 // sort out what kind of clip mask needs to be created: alpha, stencil, | 199 // sort out what kind of clip mask needs to be created: alpha, stencil, |
| 212 // scissor, or entirely software | 200 // scissor, or entirely software |
| 213 bool GrClipMaskManager::setupClipping(const GrClipData* clipDataIn, | 201 bool GrClipMaskManager::setupClipping(GrDrawState* drawState, |
| 214 const SkRect* devBounds, | |
| 215 GrDrawState::AutoRestoreEffects* are, | 202 GrDrawState::AutoRestoreEffects* are, |
| 216 GrDrawState::AutoRestoreStencil* ars, | 203 GrDrawState::AutoRestoreStencil* ars, |
| 217 ScissorState* scissorState) { | 204 ScissorState* scissorState, |
| 205 const GrClipData* clipDataIn, |
| 206 const SkRect* devBounds) { |
| 218 fCurrClipMaskType = kNone_ClipMaskType; | 207 fCurrClipMaskType = kNone_ClipMaskType; |
| 219 if (kRespectClip_StencilClipMode == fClipMode) { | 208 if (kRespectClip_StencilClipMode == fClipMode) { |
| 220 fClipMode = kIgnoreClip_StencilClipMode; | 209 fClipMode = kIgnoreClip_StencilClipMode; |
| 221 } | 210 } |
| 222 | 211 |
| 223 GrReducedClip::ElementList elements(16); | 212 GrReducedClip::ElementList elements(16); |
| 224 int32_t genID; | 213 int32_t genID; |
| 225 GrReducedClip::InitialState initialState; | 214 GrReducedClip::InitialState initialState; |
| 226 SkIRect clipSpaceIBounds; | 215 SkIRect clipSpaceIBounds; |
| 227 bool requiresAA; | 216 bool requiresAA; |
| 217 GrRenderTarget* rt = drawState->getRenderTarget(); |
| 228 | 218 |
| 229 GrDrawState* drawState = fClipTarget->drawState(); | |
| 230 | |
| 231 const GrRenderTarget* rt = drawState->getRenderTarget(); | |
| 232 // GrDrawTarget should have filtered this for us | 219 // GrDrawTarget should have filtered this for us |
| 233 SkASSERT(rt); | 220 SkASSERT(rt); |
| 234 | 221 |
| 235 bool ignoreClip = !drawState->isClipState() || clipDataIn->fClipStack->isWid
eOpen(); | 222 bool ignoreClip = !drawState->isClipState() || clipDataIn->fClipStack->isWid
eOpen(); |
| 236 if (!ignoreClip) { | 223 if (!ignoreClip) { |
| 237 SkIRect clipSpaceRTIBounds = SkIRect::MakeWH(rt->width(), rt->height()); | 224 SkIRect clipSpaceRTIBounds = SkIRect::MakeWH(rt->width(), rt->height()); |
| 238 clipSpaceRTIBounds.offset(clipDataIn->fOrigin); | 225 clipSpaceRTIBounds.offset(clipDataIn->fOrigin); |
| 239 GrReducedClip::ReduceClipStack(*clipDataIn->fClipStack, | 226 GrReducedClip::ReduceClipStack(*clipDataIn->fClipStack, |
| 240 clipSpaceRTIBounds, | 227 clipSpaceRTIBounds, |
| 241 &elements, | 228 &elements, |
| 242 &genID, | 229 &genID, |
| 243 &initialState, | 230 &initialState, |
| 244 &clipSpaceIBounds, | 231 &clipSpaceIBounds, |
| 245 &requiresAA); | 232 &requiresAA); |
| 246 if (elements.isEmpty()) { | 233 if (elements.isEmpty()) { |
| 247 if (GrReducedClip::kAllIn_InitialState == initialState) { | 234 if (GrReducedClip::kAllIn_InitialState == initialState) { |
| 248 ignoreClip = clipSpaceIBounds == clipSpaceRTIBounds; | 235 ignoreClip = clipSpaceIBounds == clipSpaceRTIBounds; |
| 249 } else { | 236 } else { |
| 250 return false; | 237 return false; |
| 251 } | 238 } |
| 252 } | 239 } |
| 253 } | 240 } |
| 254 | 241 |
| 255 if (ignoreClip) { | 242 if (ignoreClip) { |
| 256 this->setDrawStateStencil(ars); | 243 this->setDrawStateStencil(drawState, ars); |
| 257 return true; | 244 return true; |
| 258 } | 245 } |
| 259 | 246 |
| 260 // An element count of 4 was chosen because of the common pattern in Blink o
f: | 247 // An element count of 4 was chosen because of the common pattern in Blink o
f: |
| 261 // isect RR | 248 // isect RR |
| 262 // diff RR | 249 // diff RR |
| 263 // isect convex_poly | 250 // isect convex_poly |
| 264 // isect convex_poly | 251 // isect convex_poly |
| 265 // when drawing rounded div borders. This could probably be tuned based on a | 252 // when drawing rounded div borders. This could probably be tuned based on a |
| 266 // configuration's relative costs of switching RTs to generate a mask vs | 253 // configuration's relative costs of switching RTs to generate a mask vs |
| 267 // longer shaders. | 254 // longer shaders. |
| 268 if (elements.count() <= 4) { | 255 if (elements.count() <= 4) { |
| 269 SkVector clipToRTOffset = { SkIntToScalar(-clipDataIn->fOrigin.fX), | 256 SkVector clipToRTOffset = { SkIntToScalar(-clipDataIn->fOrigin.fX), |
| 270 SkIntToScalar(-clipDataIn->fOrigin.fY) }; | 257 SkIntToScalar(-clipDataIn->fOrigin.fY) }; |
| 271 if (elements.isEmpty() || | 258 if (elements.isEmpty() || |
| 272 (requiresAA && this->installClipEffects(elements, are, clipToRTOffse
t, devBounds))) { | 259 (requiresAA && this->installClipEffects(drawState, are, elements, cl
ipToRTOffset, |
| 260 devBounds))) { |
| 273 SkIRect scissorSpaceIBounds(clipSpaceIBounds); | 261 SkIRect scissorSpaceIBounds(clipSpaceIBounds); |
| 274 scissorSpaceIBounds.offset(-clipDataIn->fOrigin); | 262 scissorSpaceIBounds.offset(-clipDataIn->fOrigin); |
| 275 if (NULL == devBounds || | 263 if (NULL == devBounds || |
| 276 !SkRect::Make(scissorSpaceIBounds).contains(*devBounds)) { | 264 !SkRect::Make(scissorSpaceIBounds).contains(*devBounds)) { |
| 277 scissorState->set(scissorSpaceIBounds); | 265 scissorState->set(scissorSpaceIBounds); |
| 278 } | 266 } |
| 279 this->setDrawStateStencil(ars); | 267 this->setDrawStateStencil(drawState, ars); |
| 280 return true; | 268 return true; |
| 281 } | 269 } |
| 282 } | 270 } |
| 283 | 271 |
| 284 #if GR_AA_CLIP | 272 #if GR_AA_CLIP |
| 285 // If MSAA is enabled we can do everything in the stencil buffer. | 273 // If MSAA is enabled we can do everything in the stencil buffer. |
| 286 if (0 == rt->numSamples() && requiresAA) { | 274 if (0 == rt->numSamples() && requiresAA) { |
| 287 GrTexture* result = NULL; | 275 GrTexture* result = NULL; |
| 288 | 276 |
| 289 if (this->useSWOnlyPath(elements)) { | 277 if (this->useSWOnlyPath(drawState, elements)) { |
| 290 // The clip geometry is complex enough that it will be more efficien
t to create it | 278 // The clip geometry is complex enough that it will be more efficien
t to create it |
| 291 // entirely in software | 279 // entirely in software |
| 292 result = this->createSoftwareClipMask(genID, | 280 result = this->createSoftwareClipMask(genID, |
| 293 initialState, | 281 initialState, |
| 294 elements, | 282 elements, |
| 295 clipSpaceIBounds); | 283 clipSpaceIBounds); |
| 296 } else { | 284 } else { |
| 297 result = this->createAlphaClipMask(genID, | 285 result = this->createAlphaClipMask(genID, |
| 298 initialState, | 286 initialState, |
| 299 elements, | 287 elements, |
| 300 clipSpaceIBounds); | 288 clipSpaceIBounds); |
| 301 } | 289 } |
| 302 | 290 |
| 303 if (result) { | 291 if (result) { |
| 304 // The mask's top left coord should be pinned to the rounded-out top
left corner of | 292 // The mask's top left coord should be pinned to the rounded-out top
left corner of |
| 305 // clipSpace bounds. We determine the mask's position WRT to the ren
der target here. | 293 // clipSpace bounds. We determine the mask's position WRT to the ren
der target here. |
| 306 SkIRect rtSpaceMaskBounds = clipSpaceIBounds; | 294 SkIRect rtSpaceMaskBounds = clipSpaceIBounds; |
| 307 rtSpaceMaskBounds.offset(-clipDataIn->fOrigin); | 295 rtSpaceMaskBounds.offset(-clipDataIn->fOrigin); |
| 308 are->set(fClipTarget->drawState()); | 296 setup_drawstate_aaclip(rtSpaceMaskBounds, drawState, result); |
| 309 setup_drawstate_aaclip(fClipTarget, result, rtSpaceMaskBounds); | 297 this->setDrawStateStencil(drawState, ars); |
| 310 this->setDrawStateStencil(ars); | |
| 311 return true; | 298 return true; |
| 312 } | 299 } |
| 313 // if alpha clip mask creation fails fall through to the non-AA code pat
hs | 300 // if alpha clip mask creation fails fall through to the non-AA code pat
hs |
| 314 } | 301 } |
| 315 #endif // GR_AA_CLIP | 302 #endif // GR_AA_CLIP |
| 316 | 303 |
| 317 // Either a hard (stencil buffer) clip was explicitly requested or an anti-a
liased clip couldn't | 304 // Either a hard (stencil buffer) clip was explicitly requested or an anti-a
liased clip couldn't |
| 318 // be created. In either case, free up the texture in the anti-aliased mask
cache. | 305 // be created. In either case, free up the texture in the anti-aliased mask
cache. |
| 319 // TODO: this may require more investigation. Ganesh performs a lot of utili
ty draws (e.g., | 306 // TODO: this may require more investigation. Ganesh performs a lot of utili
ty draws (e.g., |
| 320 // clears, InOrderDrawBuffer playbacks) that hit the stencil buffer path. Th
ese may be | 307 // clears, InOrderDrawBuffer playbacks) that hit the stencil buffer path. Th
ese may be |
| 321 // "incorrectly" clearing the AA cache. | 308 // "incorrectly" clearing the AA cache. |
| 322 fAACache.reset(); | 309 fAACache.reset(); |
| 323 | 310 |
| 324 // use the stencil clip if we can't represent the clip as a rectangle. | 311 // use the stencil clip if we can't represent the clip as a rectangle. |
| 325 SkIPoint clipSpaceToStencilSpaceOffset = -clipDataIn->fOrigin; | 312 SkIPoint clipSpaceToStencilSpaceOffset = -clipDataIn->fOrigin; |
| 326 this->createStencilClipMask(genID, | 313 this->createStencilClipMask(rt, |
| 314 genID, |
| 327 initialState, | 315 initialState, |
| 328 elements, | 316 elements, |
| 329 clipSpaceIBounds, | 317 clipSpaceIBounds, |
| 330 clipSpaceToStencilSpaceOffset); | 318 clipSpaceToStencilSpaceOffset); |
| 331 | 319 |
| 332 // This must occur after createStencilClipMask. That function may change the
scissor. Also, it | 320 // This must occur after createStencilClipMask. That function may change the
scissor. Also, it |
| 333 // only guarantees that the stencil mask is correct within the bounds it was
passed, so we must | 321 // only guarantees that the stencil mask is correct within the bounds it was
passed, so we must |
| 334 // use both stencil and scissor test to the bounds for the final draw. | 322 // use both stencil and scissor test to the bounds for the final draw. |
| 335 SkIRect scissorSpaceIBounds(clipSpaceIBounds); | 323 SkIRect scissorSpaceIBounds(clipSpaceIBounds); |
| 336 scissorSpaceIBounds.offset(clipSpaceToStencilSpaceOffset); | 324 scissorSpaceIBounds.offset(clipSpaceToStencilSpaceOffset); |
| 337 scissorState->set(scissorSpaceIBounds); | 325 scissorState->set(scissorSpaceIBounds); |
| 338 this->setDrawStateStencil(ars); | 326 this->setDrawStateStencil(drawState, ars); |
| 339 return true; | 327 return true; |
| 340 } | 328 } |
| 341 | 329 |
| 342 #define VISUALIZE_COMPLEX_CLIP 0 | |
| 343 | |
| 344 #if VISUALIZE_COMPLEX_CLIP | |
| 345 #include "SkRandom.h" | |
| 346 SkRandom gRandom; | |
| 347 #define SET_RANDOM_COLOR drawState->setColor(0xff000000 | gRandom.nextU()); | |
| 348 #else | |
| 349 #define SET_RANDOM_COLOR | |
| 350 #endif | |
| 351 | |
| 352 namespace { | 330 namespace { |
| 353 | |
| 354 //////////////////////////////////////////////////////////////////////////////// | 331 //////////////////////////////////////////////////////////////////////////////// |
| 355 // set up the OpenGL blend function to perform the specified | 332 // set up the OpenGL blend function to perform the specified |
| 356 // boolean operation for alpha clip mask creation | 333 // boolean operation for alpha clip mask creation |
| 357 void setup_boolean_blendcoeffs(GrDrawState* drawState, SkRegion::Op op) { | 334 void setup_boolean_blendcoeffs(SkRegion::Op op, GrDrawState* drawState) { |
| 358 | |
| 359 switch (op) { | 335 switch (op) { |
| 360 case SkRegion::kReplace_Op: | 336 case SkRegion::kReplace_Op: |
| 361 drawState->setBlendFunc(kOne_GrBlendCoeff, kZero_GrBlendCoeff); | 337 drawState->setBlendFunc(kOne_GrBlendCoeff, kZero_GrBlendCoeff); |
| 362 break; | 338 break; |
| 363 case SkRegion::kIntersect_Op: | 339 case SkRegion::kIntersect_Op: |
| 364 drawState->setBlendFunc(kDC_GrBlendCoeff, kZero_GrBlendCoeff); | 340 drawState->setBlendFunc(kDC_GrBlendCoeff, kZero_GrBlendCoeff); |
| 365 break; | 341 break; |
| 366 case SkRegion::kUnion_Op: | 342 case SkRegion::kUnion_Op: |
| 367 drawState->setBlendFunc(kOne_GrBlendCoeff, kISC_GrBlendCoeff); | 343 drawState->setBlendFunc(kOne_GrBlendCoeff, kISC_GrBlendCoeff); |
| 368 break; | 344 break; |
| 369 case SkRegion::kXOR_Op: | 345 case SkRegion::kXOR_Op: |
| 370 drawState->setBlendFunc(kIDC_GrBlendCoeff, kISC_GrBlendCoeff); | 346 drawState->setBlendFunc(kIDC_GrBlendCoeff, kISC_GrBlendCoeff); |
| 371 break; | 347 break; |
| 372 case SkRegion::kDifference_Op: | 348 case SkRegion::kDifference_Op: |
| 373 drawState->setBlendFunc(kZero_GrBlendCoeff, kISC_GrBlendCoeff); | 349 drawState->setBlendFunc(kZero_GrBlendCoeff, kISC_GrBlendCoeff); |
| 374 break; | 350 break; |
| 375 case SkRegion::kReverseDifference_Op: | 351 case SkRegion::kReverseDifference_Op: |
| 376 drawState->setBlendFunc(kIDC_GrBlendCoeff, kZero_GrBlendCoeff); | 352 drawState->setBlendFunc(kIDC_GrBlendCoeff, kZero_GrBlendCoeff); |
| 377 break; | 353 break; |
| 378 default: | 354 default: |
| 379 SkASSERT(false); | 355 SkASSERT(false); |
| 380 break; | 356 break; |
| 381 } | 357 } |
| 382 } | 358 } |
| 383 | |
| 384 } | 359 } |
| 385 | 360 |
| 386 //////////////////////////////////////////////////////////////////////////////// | 361 //////////////////////////////////////////////////////////////////////////////// |
| 387 bool GrClipMaskManager::drawElement(GrTexture* target, | 362 bool GrClipMaskManager::drawElement(GrDrawState* drawState, |
| 363 GrTexture* target, |
| 388 const SkClipStack::Element* element, | 364 const SkClipStack::Element* element, |
| 389 GrPathRenderer* pr) { | 365 GrPathRenderer* pr) { |
| 390 GrDrawState* drawState = fClipTarget->drawState(); | 366 GrDrawTarget::AutoGeometryPush agp(fClipTarget); |
| 391 | 367 |
| 392 drawState->setRenderTarget(target->asRenderTarget()); | 368 drawState->setRenderTarget(target->asRenderTarget()); |
| 393 | 369 |
| 394 // TODO: Draw rrects directly here. | 370 // TODO: Draw rrects directly here. |
| 395 switch (element->getType()) { | 371 switch (element->getType()) { |
| 396 case Element::kEmpty_Type: | 372 case Element::kEmpty_Type: |
| 397 SkDEBUGFAIL("Should never get here with an empty element."); | 373 SkDEBUGFAIL("Should never get here with an empty element."); |
| 398 break; | 374 break; |
| 399 case Element::kRect_Type: | 375 case Element::kRect_Type: |
| 400 // TODO: Do rects directly to the accumulator using a aa-rect GrProc
essor that covers | 376 // TODO: Do rects directly to the accumulator using a aa-rect GrProc
essor that covers |
| 401 // the entire mask bounds and writes 0 outside the rect. | 377 // the entire mask bounds and writes 0 outside the rect. |
| 402 if (element->isAA()) { | 378 if (element->isAA()) { |
| 403 this->getContext()->getAARectRenderer()->fillAARect(fClipTarget, | 379 this->getContext()->getAARectRenderer()->fillAARect(fClipTarget, |
| 380 drawState, |
| 404 element->get
Rect(), | 381 element->get
Rect(), |
| 405 SkMatrix::I(
), | 382 SkMatrix::I(
), |
| 406 element->get
Rect()); | 383 element->get
Rect()); |
| 407 } else { | 384 } else { |
| 408 fClipTarget->drawSimpleRect(element->getRect()); | 385 fClipTarget->drawSimpleRect(drawState, element->getRect()); |
| 409 } | 386 } |
| 410 return true; | 387 return true; |
| 411 default: { | 388 default: { |
| 412 SkPath path; | 389 SkPath path; |
| 413 element->asPath(&path); | 390 element->asPath(&path); |
| 414 path.setIsVolatile(true); | 391 path.setIsVolatile(true); |
| 415 if (path.isInverseFillType()) { | 392 if (path.isInverseFillType()) { |
| 416 path.toggleInverseFillType(); | 393 path.toggleInverseFillType(); |
| 417 } | 394 } |
| 418 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); | 395 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); |
| 419 if (NULL == pr) { | 396 if (NULL == pr) { |
| 420 GrPathRendererChain::DrawType type; | 397 GrPathRendererChain::DrawType type; |
| 421 type = element->isAA() ? GrPathRendererChain::kColorAntiAlias_Dr
awType : | 398 type = element->isAA() ? GrPathRendererChain::kColorAntiAlias_Dr
awType : |
| 422 GrPathRendererChain::kColor_DrawType; | 399 GrPathRendererChain::kColor_DrawType; |
| 423 pr = this->getContext()->getPathRenderer(path, stroke, fClipTarg
et, false, type); | 400 pr = this->getContext()->getPathRenderer(fClipTarget, drawState,
path, stroke, |
| 401 false, type); |
| 424 } | 402 } |
| 425 if (NULL == pr) { | 403 if (NULL == pr) { |
| 426 return false; | 404 return false; |
| 427 } | 405 } |
| 428 pr->drawPath(path, stroke, fClipTarget, element->isAA()); | 406 |
| 407 pr->drawPath(fClipTarget, drawState, path, stroke, element->isAA()); |
| 429 break; | 408 break; |
| 430 } | 409 } |
| 431 } | 410 } |
| 432 return true; | 411 return true; |
| 433 } | 412 } |
| 434 | 413 |
| 435 bool GrClipMaskManager::canStencilAndDrawElement(GrTexture* target, | 414 bool GrClipMaskManager::canStencilAndDrawElement(GrDrawState* drawState, |
| 436 const SkClipStack::Element* ele
ment, | 415 GrTexture* target, |
| 437 GrPathRenderer** pr) { | 416 GrPathRenderer** pr, |
| 438 GrDrawState* drawState = fClipTarget->drawState(); | 417 const SkClipStack::Element* ele
ment) { |
| 439 drawState->setRenderTarget(target->asRenderTarget()); | 418 drawState->setRenderTarget(target->asRenderTarget()); |
| 440 | 419 |
| 441 if (Element::kRect_Type == element->getType()) { | 420 if (Element::kRect_Type == element->getType()) { |
| 442 return true; | 421 return true; |
| 443 } else { | 422 } else { |
| 444 // We shouldn't get here with an empty clip element. | 423 // We shouldn't get here with an empty clip element. |
| 445 SkASSERT(Element::kEmpty_Type != element->getType()); | 424 SkASSERT(Element::kEmpty_Type != element->getType()); |
| 446 SkPath path; | 425 SkPath path; |
| 447 element->asPath(&path); | 426 element->asPath(&path); |
| 448 if (path.isInverseFillType()) { | 427 if (path.isInverseFillType()) { |
| 449 path.toggleInverseFillType(); | 428 path.toggleInverseFillType(); |
| 450 } | 429 } |
| 451 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); | 430 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); |
| 452 GrPathRendererChain::DrawType type = element->isAA() ? | 431 GrPathRendererChain::DrawType type = element->isAA() ? |
| 453 GrPathRendererChain::kStencilAndColorAntiAlias_DrawType : | 432 GrPathRendererChain::kStencilAndColorAntiAlias_DrawType : |
| 454 GrPathRendererChain::kStencilAndColor_DrawType; | 433 GrPathRendererChain::kStencilAndColor_DrawType; |
| 455 *pr = this->getContext()->getPathRenderer(path, stroke, fClipTarget, fal
se, type); | 434 *pr = this->getContext()->getPathRenderer(fClipTarget, drawState, path,
stroke, false, |
| 435 type); |
| 456 return SkToBool(*pr); | 436 return SkToBool(*pr); |
| 457 } | 437 } |
| 458 } | 438 } |
| 459 | 439 |
| 460 void GrClipMaskManager::mergeMask(GrTexture* dstMask, | 440 void GrClipMaskManager::mergeMask(GrDrawState* drawState, |
| 441 GrTexture* dstMask, |
| 461 GrTexture* srcMask, | 442 GrTexture* srcMask, |
| 462 SkRegion::Op op, | 443 SkRegion::Op op, |
| 463 const SkIRect& dstBound, | 444 const SkIRect& dstBound, |
| 464 const SkIRect& srcBound) { | 445 const SkIRect& srcBound) { |
| 465 GrDrawState::AutoViewMatrixRestore avmr; | 446 SkAssertResult(drawState->setIdentityViewMatrix()); |
| 466 GrDrawState* drawState = fClipTarget->drawState(); | |
| 467 SkAssertResult(avmr.setIdentity(drawState)); | |
| 468 GrDrawState::AutoRestoreEffects are(drawState); | |
| 469 | 447 |
| 470 drawState->setRenderTarget(dstMask->asRenderTarget()); | 448 drawState->setRenderTarget(dstMask->asRenderTarget()); |
| 471 | 449 |
| 472 setup_boolean_blendcoeffs(drawState, op); | 450 setup_boolean_blendcoeffs(op, drawState); |
| 473 | 451 |
| 474 SkMatrix sampleM; | 452 SkMatrix sampleM; |
| 475 sampleM.setIDiv(srcMask->width(), srcMask->height()); | 453 sampleM.setIDiv(srcMask->width(), srcMask->height()); |
| 476 | 454 |
| 477 drawState->addColorProcessor( | 455 drawState->addColorProcessor( |
| 478 GrTextureDomainEffect::Create(srcMask, | 456 GrTextureDomainEffect::Create(srcMask, |
| 479 sampleM, | 457 sampleM, |
| 480 GrTextureDomain::MakeTexelDomain(srcMask,
srcBound), | 458 GrTextureDomain::MakeTexelDomain(srcMask,
srcBound), |
| 481 GrTextureDomain::kDecal_Mode, | 459 GrTextureDomain::kDecal_Mode, |
| 482 GrTextureParams::kNone_FilterMode))->unref
(); | 460 GrTextureParams::kNone_FilterMode))->unref
(); |
| 483 fClipTarget->drawSimpleRect(SkRect::Make(dstBound)); | 461 fClipTarget->drawSimpleRect(drawState, SkRect::Make(dstBound)); |
| 484 } | 462 } |
| 485 | 463 |
| 486 GrTexture* GrClipMaskManager::createTempMask(int width, int height) { | 464 GrTexture* GrClipMaskManager::createTempMask(int width, int height) { |
| 487 GrSurfaceDesc desc; | 465 GrSurfaceDesc desc; |
| 488 desc.fFlags = kRenderTarget_GrSurfaceFlag|kNoStencil_GrSurfaceFlag; | 466 desc.fFlags = kRenderTarget_GrSurfaceFlag|kNoStencil_GrSurfaceFlag; |
| 489 desc.fWidth = width; | 467 desc.fWidth = width; |
| 490 desc.fHeight = height; | 468 desc.fHeight = height; |
| 491 desc.fConfig = kAlpha_8_GrPixelConfig; | 469 desc.fConfig = kAlpha_8_GrPixelConfig; |
| 492 | 470 |
| 493 return this->getContext()->refScratchTexture(desc, GrContext::kApprox_Scratc
hTexMatch); | 471 return this->getContext()->refScratchTexture(desc, GrContext::kApprox_Scratc
hTexMatch); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 556 SkIntToScalar(-clipSpaceIBounds.fLeft), | 534 SkIntToScalar(-clipSpaceIBounds.fLeft), |
| 557 SkIntToScalar(-clipSpaceIBounds.fTop) | 535 SkIntToScalar(-clipSpaceIBounds.fTop) |
| 558 }; | 536 }; |
| 559 // The texture may be larger than necessary, this rect represents the part o
f the texture | 537 // The texture may be larger than necessary, this rect represents the part o
f the texture |
| 560 // we populate with a rasterization of the clip. | 538 // we populate with a rasterization of the clip. |
| 561 SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpa
ceIBounds.height()); | 539 SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpa
ceIBounds.height()); |
| 562 | 540 |
| 563 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip space. | 541 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip space. |
| 564 SkMatrix translate; | 542 SkMatrix translate; |
| 565 translate.setTranslate(clipToMaskOffset); | 543 translate.setTranslate(clipToMaskOffset); |
| 566 GrDrawTarget::AutoGeometryAndStatePush agasp(fClipTarget, GrDrawTarget::kRes
et_ASRInit, | |
| 567 &translate); | |
| 568 | |
| 569 GrDrawState* drawState = fClipTarget->drawState(); | |
| 570 | |
| 571 // We're drawing a coverage mask and want coverage to be run through the ble
nd function. | |
| 572 drawState->enableState(GrDrawState::kCoverageDrawing_StateBit); | |
| 573 | 544 |
| 574 // The scratch texture that we are drawing into can be substantially larger
than the mask. Only | 545 // The scratch texture that we are drawing into can be substantially larger
than the mask. Only |
| 575 // clear the part that we care about. | 546 // clear the part that we care about. |
| 576 fClipTarget->clear(&maskSpaceIBounds, | 547 fClipTarget->clear(&maskSpaceIBounds, |
| 577 GrReducedClip::kAllIn_InitialState == initialState ? 0xff
ffffff : 0x00000000, | 548 GrReducedClip::kAllIn_InitialState == initialState ? 0xff
ffffff : 0x00000000, |
| 578 true, | 549 true, |
| 579 result->asRenderTarget()); | 550 result->asRenderTarget()); |
| 580 | 551 |
| 581 // When we use the stencil in the below loop it is important to have this cl
ip installed. | 552 // When we use the stencil in the below loop it is important to have this cl
ip installed. |
| 582 // The second pass that zeros the stencil buffer renders the rect maskSpaceI
Bounds so the first | 553 // The second pass that zeros the stencil buffer renders the rect maskSpaceI
Bounds so the first |
| 583 // pass must not set values outside of this bounds or stencil values outside
the rect won't be | 554 // pass must not set values outside of this bounds or stencil values outside
the rect won't be |
| 584 // cleared. | 555 // cleared. |
| 585 GrDrawTarget::AutoClipRestore acr(fClipTarget, maskSpaceIBounds); | 556 GrDrawTarget::AutoClipRestore acr(fClipTarget, maskSpaceIBounds); |
| 586 drawState->enableState(GrDrawState::kClip_StateBit); | 557 SkAutoTUnref<GrTexture> temp; |
| 587 | 558 |
| 588 SkAutoTUnref<GrTexture> temp; | |
| 589 // walk through each clip element and perform its set op | 559 // walk through each clip element and perform its set op |
| 590 for (GrReducedClip::ElementList::Iter iter = elements.headIter(); iter.get()
; iter.next()) { | 560 for (GrReducedClip::ElementList::Iter iter = elements.headIter(); iter.get()
; iter.next()) { |
| 591 const Element* element = iter.get(); | 561 const Element* element = iter.get(); |
| 592 SkRegion::Op op = element->getOp(); | 562 SkRegion::Op op = element->getOp(); |
| 593 bool invert = element->isInverseFilled(); | 563 bool invert = element->isInverseFilled(); |
| 564 if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDiffere
nce_Op == op) { |
| 565 GrDrawState drawState(translate); |
| 566 // We're drawing a coverage mask and want coverage to be run through
the blend function. |
| 567 drawState.enableState(GrDrawState::kCoverageDrawing_StateBit | |
| 568 GrDrawState::kClip_StateBit); |
| 594 | 569 |
| 595 if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDiffere
nce_Op == op) { | |
| 596 GrPathRenderer* pr = NULL; | 570 GrPathRenderer* pr = NULL; |
| 597 bool useTemp = !this->canStencilAndDrawElement(result, element, &pr)
; | 571 bool useTemp = !this->canStencilAndDrawElement(&drawState, result, &
pr, element); |
| 598 GrTexture* dst; | 572 GrTexture* dst; |
| 599 // This is the bounds of the clip element in the space of the alpha-
mask. The temporary | 573 // This is the bounds of the clip element in the space of the alpha-
mask. The temporary |
| 600 // mask buffer can be substantially larger than the actually clip st
ack element. We | 574 // mask buffer can be substantially larger than the actually clip st
ack element. We |
| 601 // touch the minimum number of pixels necessary and use decal mode t
o combine it with | 575 // touch the minimum number of pixels necessary and use decal mode t
o combine it with |
| 602 // the accumulator. | 576 // the accumulator. |
| 603 SkIRect maskSpaceElementIBounds; | 577 SkIRect maskSpaceElementIBounds; |
| 604 | 578 |
| 605 if (useTemp) { | 579 if (useTemp) { |
| 606 if (invert) { | 580 if (invert) { |
| 607 maskSpaceElementIBounds = maskSpaceIBounds; | 581 maskSpaceElementIBounds = maskSpaceIBounds; |
| 608 } else { | 582 } else { |
| 609 SkRect elementBounds = element->getBounds(); | 583 SkRect elementBounds = element->getBounds(); |
| 610 elementBounds.offset(clipToMaskOffset); | 584 elementBounds.offset(clipToMaskOffset); |
| 611 elementBounds.roundOut(&maskSpaceElementIBounds); | 585 elementBounds.roundOut(&maskSpaceElementIBounds); |
| 612 } | 586 } |
| 613 | 587 |
| 614 if (!temp) { | 588 if (!temp) { |
| 615 temp.reset(this->createTempMask(maskSpaceIBounds.fRight, | 589 temp.reset(this->createTempMask(maskSpaceIBounds.fRight, |
| 616 maskSpaceIBounds.fBottom)); | 590 maskSpaceIBounds.fBottom)); |
| 617 if (!temp) { | 591 if (!temp) { |
| 618 fAACache.reset(); | 592 fAACache.reset(); |
| 619 return NULL; | 593 return NULL; |
| 620 } | 594 } |
| 621 } | 595 } |
| 622 dst = temp; | 596 dst = temp; |
| 623 // clear the temp target and set blend to replace | 597 // clear the temp target and set blend to replace |
| 624 fClipTarget->clear(&maskSpaceElementIBounds, | 598 fClipTarget->clear(&maskSpaceElementIBounds, |
| 625 invert ? 0xffffffff : 0x00000000, | 599 invert ? 0xffffffff : 0x00000000, |
| 626 true, | 600 true, |
| 627 dst->asRenderTarget()); | 601 dst->asRenderTarget()); |
| 628 setup_boolean_blendcoeffs(drawState, SkRegion::kReplace_Op); | 602 setup_boolean_blendcoeffs(SkRegion::kReplace_Op, &drawState); |
| 629 | |
| 630 } else { | 603 } else { |
| 631 // draw directly into the result with the stencil set to make th
e pixels affected | 604 // draw directly into the result with the stencil set to make th
e pixels affected |
| 632 // by the clip shape be non-zero. | 605 // by the clip shape be non-zero. |
| 633 dst = result; | 606 dst = result; |
| 634 GR_STATIC_CONST_SAME_STENCIL(kStencilInElement, | 607 GR_STATIC_CONST_SAME_STENCIL(kStencilInElement, |
| 635 kReplace_StencilOp, | 608 kReplace_StencilOp, |
| 636 kReplace_StencilOp, | 609 kReplace_StencilOp, |
| 637 kAlways_StencilFunc, | 610 kAlways_StencilFunc, |
| 638 0xffff, | 611 0xffff, |
| 639 0xffff, | 612 0xffff, |
| 640 0xffff); | 613 0xffff); |
| 641 drawState->setStencil(kStencilInElement); | 614 drawState.setStencil(kStencilInElement); |
| 642 setup_boolean_blendcoeffs(drawState, op); | 615 setup_boolean_blendcoeffs(op, &drawState); |
| 643 } | 616 } |
| 644 | 617 |
| 645 drawState->setAlpha(invert ? 0x00 : 0xff); | 618 drawState.setAlpha(invert ? 0x00 : 0xff); |
| 646 | 619 |
| 647 if (!this->drawElement(dst, element, pr)) { | 620 // We have to backup the drawstate because the drawElement call may
call into |
| 621 // renderers which consume it. |
| 622 GrDrawState backupDrawState(drawState); |
| 623 |
| 624 if (!this->drawElement(&drawState, dst, element, pr)) { |
| 648 fAACache.reset(); | 625 fAACache.reset(); |
| 649 return NULL; | 626 return NULL; |
| 650 } | 627 } |
| 651 | 628 |
| 652 if (useTemp) { | 629 if (useTemp) { |
| 653 // Now draw into the accumulator using the real operation and th
e temp buffer as a | 630 // Now draw into the accumulator using the real operation and th
e temp buffer as a |
| 654 // texture | 631 // texture |
| 655 this->mergeMask(result, | 632 this->mergeMask(&backupDrawState, |
| 633 result, |
| 656 temp, | 634 temp, |
| 657 op, | 635 op, |
| 658 maskSpaceIBounds, | 636 maskSpaceIBounds, |
| 659 maskSpaceElementIBounds); | 637 maskSpaceElementIBounds); |
| 660 } else { | 638 } else { |
| 661 // Draw to the exterior pixels (those with a zero stencil value)
. | 639 // Draw to the exterior pixels (those with a zero stencil value)
. |
| 662 drawState->setAlpha(invert ? 0xff : 0x00); | 640 backupDrawState.setAlpha(invert ? 0xff : 0x00); |
| 663 GR_STATIC_CONST_SAME_STENCIL(kDrawOutsideElement, | 641 GR_STATIC_CONST_SAME_STENCIL(kDrawOutsideElement, |
| 664 kZero_StencilOp, | 642 kZero_StencilOp, |
| 665 kZero_StencilOp, | 643 kZero_StencilOp, |
| 666 kEqual_StencilFunc, | 644 kEqual_StencilFunc, |
| 667 0xffff, | 645 0xffff, |
| 668 0x0000, | 646 0x0000, |
| 669 0xffff); | 647 0xffff); |
| 670 drawState->setStencil(kDrawOutsideElement); | 648 backupDrawState.setStencil(kDrawOutsideElement); |
| 671 fClipTarget->drawSimpleRect(clipSpaceIBounds); | 649 fClipTarget->drawSimpleRect(&backupDrawState, clipSpaceIBounds); |
| 672 drawState->disableStencil(); | |
| 673 } | 650 } |
| 674 } else { | 651 } else { |
| 652 GrDrawState drawState(translate); |
| 653 drawState.enableState(GrDrawState::kCoverageDrawing_StateBit | |
| 654 GrDrawState::kClip_StateBit); |
| 655 |
| 675 // all the remaining ops can just be directly draw into the accumula
tion buffer | 656 // all the remaining ops can just be directly draw into the accumula
tion buffer |
| 676 drawState->setAlpha(0xff); | 657 drawState.setAlpha(0xff); |
| 677 setup_boolean_blendcoeffs(drawState, op); | 658 setup_boolean_blendcoeffs(op, &drawState); |
| 678 this->drawElement(result, element); | 659 this->drawElement(&drawState, result, element); |
| 679 } | 660 } |
| 680 } | 661 } |
| 681 | 662 |
| 682 fCurrClipMaskType = kAlpha_ClipMaskType; | 663 fCurrClipMaskType = kAlpha_ClipMaskType; |
| 683 return result; | 664 return result; |
| 684 } | 665 } |
| 685 | 666 |
| 686 //////////////////////////////////////////////////////////////////////////////// | 667 //////////////////////////////////////////////////////////////////////////////// |
| 687 // Create a 1-bit clip mask in the stencil buffer. 'devClipBounds' are in device | 668 // Create a 1-bit clip mask in the stencil buffer. 'devClipBounds' are in device |
| 688 // (as opposed to canvas) coordinates | 669 // (as opposed to canvas) coordinates |
| 689 bool GrClipMaskManager::createStencilClipMask(int32_t elementsGenID, | 670 bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt, |
| 671 int32_t elementsGenID, |
| 690 GrReducedClip::InitialState initia
lState, | 672 GrReducedClip::InitialState initia
lState, |
| 691 const GrReducedClip::ElementList&
elements, | 673 const GrReducedClip::ElementList&
elements, |
| 692 const SkIRect& clipSpaceIBounds, | 674 const SkIRect& clipSpaceIBounds, |
| 693 const SkIPoint& clipSpaceToStencil
Offset) { | 675 const SkIPoint& clipSpaceToStencil
Offset) { |
| 694 | |
| 695 SkASSERT(kNone_ClipMaskType == fCurrClipMaskType); | 676 SkASSERT(kNone_ClipMaskType == fCurrClipMaskType); |
| 696 | |
| 697 GrDrawState* drawState = fClipTarget->drawState(); | |
| 698 SkASSERT(drawState->isClipState()); | |
| 699 | |
| 700 GrRenderTarget* rt = drawState->getRenderTarget(); | |
| 701 SkASSERT(rt); | 677 SkASSERT(rt); |
| 702 | 678 |
| 703 // TODO: dynamically attach a SB when needed. | 679 // TODO: dynamically attach a SB when needed. |
| 704 GrStencilBuffer* stencilBuffer = rt->getStencilBuffer(); | 680 GrStencilBuffer* stencilBuffer = rt->getStencilBuffer(); |
| 705 if (NULL == stencilBuffer) { | 681 if (NULL == stencilBuffer) { |
| 706 return false; | 682 return false; |
| 707 } | 683 } |
| 708 | 684 |
| 709 if (stencilBuffer->mustRenderClip(elementsGenID, clipSpaceIBounds, clipSpace
ToStencilOffset)) { | 685 if (stencilBuffer->mustRenderClip(elementsGenID, clipSpaceIBounds, clipSpace
ToStencilOffset)) { |
| 710 stencilBuffer->setLastClip(elementsGenID, clipSpaceIBounds, clipSpaceToS
tencilOffset); | 686 stencilBuffer->setLastClip(elementsGenID, clipSpaceIBounds, clipSpaceToS
tencilOffset); |
| 711 | |
| 712 // Set the matrix so that rendered clip elements are transformed from cl
ip to stencil space. | 687 // Set the matrix so that rendered clip elements are transformed from cl
ip to stencil space. |
| 713 SkVector translate = { | 688 SkVector translate = { |
| 714 SkIntToScalar(clipSpaceToStencilOffset.fX), | 689 SkIntToScalar(clipSpaceToStencilOffset.fX), |
| 715 SkIntToScalar(clipSpaceToStencilOffset.fY) | 690 SkIntToScalar(clipSpaceToStencilOffset.fY) |
| 716 }; | 691 }; |
| 717 SkMatrix matrix; | 692 SkMatrix matrix; |
| 718 matrix.setTranslate(translate); | 693 matrix.setTranslate(translate); |
| 719 GrDrawTarget::AutoGeometryAndStatePush agasp(fClipTarget, GrDrawTarget::
kReset_ASRInit, | |
| 720 &matrix); | |
| 721 drawState = fClipTarget->drawState(); | |
| 722 | |
| 723 drawState->setRenderTarget(rt); | |
| 724 | 694 |
| 725 // We set the current clip to the bounds so that our recursive draws are
scissored to them. | 695 // We set the current clip to the bounds so that our recursive draws are
scissored to them. |
| 726 SkIRect stencilSpaceIBounds(clipSpaceIBounds); | 696 SkIRect stencilSpaceIBounds(clipSpaceIBounds); |
| 727 stencilSpaceIBounds.offset(clipSpaceToStencilOffset); | 697 stencilSpaceIBounds.offset(clipSpaceToStencilOffset); |
| 728 GrDrawTarget::AutoClipRestore acr(fClipTarget, stencilSpaceIBounds); | 698 GrDrawTarget::AutoClipRestore acr(fClipTarget, stencilSpaceIBounds); |
| 729 drawState->enableState(GrDrawState::kClip_StateBit); | |
| 730 | |
| 731 #if !VISUALIZE_COMPLEX_CLIP | |
| 732 drawState->enableState(GrDrawState::kNoColorWrites_StateBit); | |
| 733 #endif | |
| 734 | 699 |
| 735 int clipBit = stencilBuffer->bits(); | 700 int clipBit = stencilBuffer->bits(); |
| 736 SkASSERT((clipBit <= 16) && "Ganesh only handles 16b or smaller stencil
buffers"); | 701 SkASSERT((clipBit <= 16) && "Ganesh only handles 16b or smaller stencil
buffers"); |
| 737 clipBit = (1 << (clipBit-1)); | 702 clipBit = (1 << (clipBit-1)); |
| 738 | 703 |
| 739 fClipTarget->clearStencilClip(stencilSpaceIBounds, | 704 fClipTarget->clearStencilClip(stencilSpaceIBounds, |
| 740 GrReducedClip::kAllIn_InitialState == init
ialState, | 705 GrReducedClip::kAllIn_InitialState == init
ialState, |
| 741 rt); | 706 rt); |
| 742 | 707 |
| 743 // walk through each clip element and perform its set op | 708 // walk through each clip element and perform its set op |
| 744 // with the existing clip. | 709 // with the existing clip. |
| 745 for (GrReducedClip::ElementList::Iter iter(elements.headIter()); iter.ge
t(); iter.next()) { | 710 for (GrReducedClip::ElementList::Iter iter(elements.headIter()); iter.ge
t(); iter.next()) { |
| 746 const Element* element = iter.get(); | 711 const Element* element = iter.get(); |
| 712 |
| 713 GrDrawState drawState(matrix); |
| 714 drawState.setRenderTarget(rt); |
| 715 drawState.enableState(GrDrawState::kClip_StateBit); |
| 716 drawState.enableState(GrDrawState::kNoColorWrites_StateBit); |
| 717 |
| 718 // if the target is MSAA then we want MSAA enabled when the clip is
soft |
| 719 if (rt->isMultisampled()) { |
| 720 drawState.setState(GrDrawState::kHWAntialias_StateBit, element->
isAA()); |
| 721 } |
| 722 |
| 747 bool fillInverted = false; | 723 bool fillInverted = false; |
| 748 // enabled at bottom of loop | 724 // enabled at bottom of loop |
| 749 fClipMode = kIgnoreClip_StencilClipMode; | 725 fClipMode = kIgnoreClip_StencilClipMode; |
| 750 // if the target is MSAA then we want MSAA enabled when the clip is
soft | |
| 751 if (rt->isMultisampled()) { | |
| 752 drawState->setState(GrDrawState::kHWAntialias_StateBit, element-
>isAA()); | |
| 753 } | |
| 754 | 726 |
| 755 // This will be used to determine whether the clip shape can be rend
ered into the | 727 // This will be used to determine whether the clip shape can be rend
ered into the |
| 756 // stencil with arbitrary stencil settings. | 728 // stencil with arbitrary stencil settings. |
| 757 GrPathRenderer::StencilSupport stencilSupport; | 729 GrPathRenderer::StencilSupport stencilSupport; |
| 758 | 730 |
| 759 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); | 731 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); |
| 760 | |
| 761 SkRegion::Op op = element->getOp(); | 732 SkRegion::Op op = element->getOp(); |
| 762 | 733 |
| 763 GrPathRenderer* pr = NULL; | 734 GrPathRenderer* pr = NULL; |
| 764 SkPath clipPath; | 735 SkPath clipPath; |
| 765 if (Element::kRect_Type == element->getType()) { | 736 if (Element::kRect_Type == element->getType()) { |
| 766 stencilSupport = GrPathRenderer::kNoRestriction_StencilSupport; | 737 stencilSupport = GrPathRenderer::kNoRestriction_StencilSupport; |
| 767 fillInverted = false; | 738 fillInverted = false; |
| 768 } else { | 739 } else { |
| 769 element->asPath(&clipPath); | 740 element->asPath(&clipPath); |
| 770 fillInverted = clipPath.isInverseFillType(); | 741 fillInverted = clipPath.isInverseFillType(); |
| 771 if (fillInverted) { | 742 if (fillInverted) { |
| 772 clipPath.toggleInverseFillType(); | 743 clipPath.toggleInverseFillType(); |
| 773 } | 744 } |
| 774 pr = this->getContext()->getPathRenderer(clipPath, | 745 pr = this->getContext()->getPathRenderer(fClipTarget, |
| 746 &drawState, |
| 747 clipPath, |
| 775 stroke, | 748 stroke, |
| 776 fClipTarget, | |
| 777 false, | 749 false, |
| 778 GrPathRendererChain::kS
tencilOnly_DrawType, | 750 GrPathRendererChain::kS
tencilOnly_DrawType, |
| 779 &stencilSupport); | 751 &stencilSupport); |
| 780 if (NULL == pr) { | 752 if (NULL == pr) { |
| 781 return false; | 753 return false; |
| 782 } | 754 } |
| 783 } | 755 } |
| 784 | 756 |
| 785 int passes; | 757 int passes; |
| 786 GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClip
Passes]; | 758 GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClip
Passes]; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 800 | 772 |
| 801 // draw the element to the client stencil bits if necessary | 773 // draw the element to the client stencil bits if necessary |
| 802 if (!canDrawDirectToClip) { | 774 if (!canDrawDirectToClip) { |
| 803 GR_STATIC_CONST_SAME_STENCIL(gDrawToStencil, | 775 GR_STATIC_CONST_SAME_STENCIL(gDrawToStencil, |
| 804 kIncClamp_StencilOp, | 776 kIncClamp_StencilOp, |
| 805 kIncClamp_StencilOp, | 777 kIncClamp_StencilOp, |
| 806 kAlways_StencilFunc, | 778 kAlways_StencilFunc, |
| 807 0xffff, | 779 0xffff, |
| 808 0x0000, | 780 0x0000, |
| 809 0xffff); | 781 0xffff); |
| 810 SET_RANDOM_COLOR | |
| 811 if (Element::kRect_Type == element->getType()) { | 782 if (Element::kRect_Type == element->getType()) { |
| 812 *drawState->stencil() = gDrawToStencil; | 783 *drawState.stencil() = gDrawToStencil; |
| 813 fClipTarget->drawSimpleRect(element->getRect()); | 784 fClipTarget->drawSimpleRect(&drawState, element->getRect()); |
| 814 } else { | 785 } else { |
| 815 if (!clipPath.isEmpty()) { | 786 if (!clipPath.isEmpty()) { |
| 787 GrDrawTarget::AutoGeometryPush agp(fClipTarget); |
| 816 if (canRenderDirectToStencil) { | 788 if (canRenderDirectToStencil) { |
| 817 *drawState->stencil() = gDrawToStencil; | 789 *drawState.stencil() = gDrawToStencil; |
| 818 pr->drawPath(clipPath, stroke, fClipTarget, false); | 790 pr->drawPath(fClipTarget, &drawState, clipPath, stro
ke, false); |
| 819 } else { | 791 } else { |
| 820 pr->stencilPath(clipPath, stroke, fClipTarget); | 792 pr->stencilPath(fClipTarget, &drawState, clipPath, s
troke); |
| 821 } | 793 } |
| 822 } | 794 } |
| 823 } | 795 } |
| 824 } | 796 } |
| 825 | 797 |
| 826 // now we modify the clip bit by rendering either the clip | 798 // now we modify the clip bit by rendering either the clip |
| 827 // element directly or a bounding rect of the entire clip. | 799 // element directly or a bounding rect of the entire clip. |
| 828 fClipMode = kModifyClip_StencilClipMode; | 800 fClipMode = kModifyClip_StencilClipMode; |
| 829 for (int p = 0; p < passes; ++p) { | 801 for (int p = 0; p < passes; ++p) { |
| 830 *drawState->stencil() = stencilSettings[p]; | 802 GrDrawState drawStateCopy(drawState); |
| 803 *drawStateCopy.stencil() = stencilSettings[p]; |
| 804 |
| 831 if (canDrawDirectToClip) { | 805 if (canDrawDirectToClip) { |
| 832 if (Element::kRect_Type == element->getType()) { | 806 if (Element::kRect_Type == element->getType()) { |
| 833 SET_RANDOM_COLOR | 807 fClipTarget->drawSimpleRect(&drawStateCopy, element->get
Rect()); |
| 834 fClipTarget->drawSimpleRect(element->getRect()); | |
| 835 } else { | 808 } else { |
| 836 SET_RANDOM_COLOR | 809 GrDrawTarget::AutoGeometryPush agp(fClipTarget); |
| 837 pr->drawPath(clipPath, stroke, fClipTarget, false); | 810 pr->drawPath(fClipTarget, &drawStateCopy, clipPath, stro
ke, false); |
| 838 } | 811 } |
| 839 } else { | 812 } else { |
| 840 SET_RANDOM_COLOR | |
| 841 // The view matrix is setup to do clip space -> stencil spac
e translation, so | 813 // The view matrix is setup to do clip space -> stencil spac
e translation, so |
| 842 // draw rect in clip space. | 814 // draw rect in clip space. |
| 843 fClipTarget->drawSimpleRect(SkRect::Make(clipSpaceIBounds)); | 815 fClipTarget->drawSimpleRect(&drawStateCopy, SkRect::Make(cli
pSpaceIBounds)); |
| 844 } | 816 } |
| 845 } | 817 } |
| 846 } | 818 } |
| 847 } | 819 } |
| 848 // set this last because recursive draws may overwrite it back to kNone. | 820 // set this last because recursive draws may overwrite it back to kNone. |
| 849 SkASSERT(kNone_ClipMaskType == fCurrClipMaskType); | 821 SkASSERT(kNone_ClipMaskType == fCurrClipMaskType); |
| 850 fCurrClipMaskType = kStencil_ClipMaskType; | 822 fCurrClipMaskType = kStencil_ClipMaskType; |
| 851 fClipMode = kRespectClip_StencilClipMode; | 823 fClipMode = kRespectClip_StencilClipMode; |
| 852 return true; | 824 return true; |
| 853 } | 825 } |
| 854 | 826 |
| 855 | |
| 856 // mapping of clip-respecting stencil funcs to normal stencil funcs | 827 // mapping of clip-respecting stencil funcs to normal stencil funcs |
| 857 // mapping depends on whether stencil-clipping is in effect. | 828 // mapping depends on whether stencil-clipping is in effect. |
| 858 static const GrStencilFunc | 829 static const GrStencilFunc |
| 859 gSpecialToBasicStencilFunc[2][kClipStencilFuncCount] = { | 830 gSpecialToBasicStencilFunc[2][kClipStencilFuncCount] = { |
| 860 {// Stencil-Clipping is DISABLED, we are effectively always inside the clip | 831 {// Stencil-Clipping is DISABLED, we are effectively always inside the clip |
| 861 // In the Clip Funcs | 832 // In the Clip Funcs |
| 862 kAlways_StencilFunc, // kAlwaysIfInClip_StencilFunc | 833 kAlways_StencilFunc, // kAlwaysIfInClip_StencilFunc |
| 863 kEqual_StencilFunc, // kEqualIfInClip_StencilFunc | 834 kEqual_StencilFunc, // kEqualIfInClip_StencilFunc |
| 864 kLess_StencilFunc, // kLessIfInClip_StencilFunc | 835 kLess_StencilFunc, // kLessIfInClip_StencilFunc |
| 865 kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc | 836 kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 898 kKeep_StencilOp, | 869 kKeep_StencilOp, |
| 899 kKeep_StencilOp, | 870 kKeep_StencilOp, |
| 900 kAlwaysIfInClip_StencilFunc, | 871 kAlwaysIfInClip_StencilFunc, |
| 901 0x0000, | 872 0x0000, |
| 902 0x0000, | 873 0x0000, |
| 903 0x0000); | 874 0x0000); |
| 904 return *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&gSettings); | 875 return *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&gSettings); |
| 905 } | 876 } |
| 906 } | 877 } |
| 907 | 878 |
| 908 void GrClipMaskManager::setDrawStateStencil(GrDrawState::AutoRestoreStencil* ars
) { | 879 void GrClipMaskManager::setDrawStateStencil(GrDrawState* drawState, |
| 880 GrDrawState::AutoRestoreStencil* ars
) { |
| 909 // We make two copies of the StencilSettings here (except in the early | 881 // We make two copies of the StencilSettings here (except in the early |
| 910 // exit scenario. One copy from draw state to the stack var. Then another | 882 // exit scenario. One copy from draw state to the stack var. Then another |
| 911 // from the stack var to the gpu. We could make this class hold a ptr to | 883 // from the stack var to the gpu. We could make this class hold a ptr to |
| 912 // GrGpu's fStencilSettings and eliminate the stack copy here. | 884 // GrGpu's fStencilSettings and eliminate the stack copy here. |
| 913 | 885 |
| 914 const GrDrawState& drawState = fClipTarget->getDrawState(); | |
| 915 | |
| 916 // use stencil for clipping if clipping is enabled and the clip | 886 // use stencil for clipping if clipping is enabled and the clip |
| 917 // has been written into the stencil. | 887 // has been written into the stencil. |
| 888 GrStencilSettings settings; |
| 918 | 889 |
| 919 GrStencilSettings settings; | |
| 920 // The GrGpu client may not be using the stencil buffer but we may need to | 890 // The GrGpu client may not be using the stencil buffer but we may need to |
| 921 // enable it in order to respect a stencil clip. | 891 // enable it in order to respect a stencil clip. |
| 922 if (drawState.getStencil().isDisabled()) { | 892 if (drawState->getStencil().isDisabled()) { |
| 923 if (GrClipMaskManager::kRespectClip_StencilClipMode == fClipMode) { | 893 if (GrClipMaskManager::kRespectClip_StencilClipMode == fClipMode) { |
| 924 settings = basic_apply_stencil_clip_settings(); | 894 settings = basic_apply_stencil_clip_settings(); |
| 925 } else { | 895 } else { |
| 926 return; | 896 return; |
| 927 } | 897 } |
| 928 } else { | 898 } else { |
| 929 settings = drawState.getStencil(); | 899 settings = drawState->getStencil(); |
| 930 } | 900 } |
| 931 | 901 |
| 932 // TODO: dynamically attach a stencil buffer | 902 // TODO: dynamically attach a stencil buffer |
| 933 int stencilBits = 0; | 903 int stencilBits = 0; |
| 934 GrStencilBuffer* stencilBuffer = drawState.getRenderTarget()->getStencilBuff
er(); | 904 GrStencilBuffer* stencilBuffer = drawState->getRenderTarget()->getStencilBuf
fer(); |
| 935 if (stencilBuffer) { | 905 if (stencilBuffer) { |
| 936 stencilBits = stencilBuffer->bits(); | 906 stencilBits = stencilBuffer->bits(); |
| 937 } | 907 } |
| 938 | 908 |
| 939 SkASSERT(fClipTarget->caps()->stencilWrapOpsSupport() || !settings.usesWrapO
p()); | 909 SkASSERT(fClipTarget->caps()->stencilWrapOpsSupport() || !settings.usesWrapO
p()); |
| 940 SkASSERT(fClipTarget->caps()->twoSidedStencilSupport() || !settings.isTwoSid
ed()); | 910 SkASSERT(fClipTarget->caps()->twoSidedStencilSupport() || !settings.isTwoSid
ed()); |
| 941 this->adjustStencilParams(&settings, fClipMode, stencilBits); | 911 this->adjustStencilParams(&settings, fClipMode, stencilBits); |
| 942 ars->set(fClipTarget->drawState()); | 912 ars->set(drawState); |
| 943 fClipTarget->drawState()->setStencil(settings); | 913 drawState->setStencil(settings); |
| 944 } | 914 } |
| 945 | 915 |
| 946 void GrClipMaskManager::adjustStencilParams(GrStencilSettings* settings, | 916 void GrClipMaskManager::adjustStencilParams(GrStencilSettings* settings, |
| 947 StencilClipMode mode, | 917 StencilClipMode mode, |
| 948 int stencilBitCnt) { | 918 int stencilBitCnt) { |
| 949 SkASSERT(stencilBitCnt > 0); | 919 SkASSERT(stencilBitCnt > 0); |
| 950 | 920 |
| 951 if (kModifyClip_StencilClipMode == mode) { | 921 if (kModifyClip_StencilClipMode == mode) { |
| 952 // We assume that this clip manager itself is drawing to the GrGpu and | 922 // We assume that this clip manager itself is drawing to the GrGpu and |
| 953 // has already setup the correct values. | 923 // has already setup the correct values. |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1038 | 1008 |
| 1039 // The mask texture may be larger than necessary. We round out the clip spac
e bounds and pin | 1009 // The mask texture may be larger than necessary. We round out the clip spac
e bounds and pin |
| 1040 // the top left corner of the resulting rect to the top left of the texture. | 1010 // the top left corner of the resulting rect to the top left of the texture. |
| 1041 SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpa
ceIBounds.height()); | 1011 SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpa
ceIBounds.height()); |
| 1042 | 1012 |
| 1043 GrSWMaskHelper helper(this->getContext()); | 1013 GrSWMaskHelper helper(this->getContext()); |
| 1044 | 1014 |
| 1045 SkMatrix matrix; | 1015 SkMatrix matrix; |
| 1046 matrix.setTranslate(SkIntToScalar(-clipSpaceIBounds.fLeft), | 1016 matrix.setTranslate(SkIntToScalar(-clipSpaceIBounds.fLeft), |
| 1047 SkIntToScalar(-clipSpaceIBounds.fTop)); | 1017 SkIntToScalar(-clipSpaceIBounds.fTop)); |
| 1018 |
| 1048 helper.init(maskSpaceIBounds, &matrix, false); | 1019 helper.init(maskSpaceIBounds, &matrix, false); |
| 1049 | |
| 1050 helper.clear(GrReducedClip::kAllIn_InitialState == initialState ? 0xFF : 0x0
0); | 1020 helper.clear(GrReducedClip::kAllIn_InitialState == initialState ? 0xFF : 0x0
0); |
| 1051 | |
| 1052 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); | 1021 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); |
| 1053 | 1022 |
| 1054 for (GrReducedClip::ElementList::Iter iter(elements.headIter()) ; iter.get()
; iter.next()) { | 1023 for (GrReducedClip::ElementList::Iter iter(elements.headIter()) ; iter.get()
; iter.next()) { |
| 1055 | |
| 1056 const Element* element = iter.get(); | 1024 const Element* element = iter.get(); |
| 1057 SkRegion::Op op = element->getOp(); | 1025 SkRegion::Op op = element->getOp(); |
| 1058 | 1026 |
| 1059 if (SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op ==
op) { | 1027 if (SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op ==
op) { |
| 1060 // Intersect and reverse difference require modifying pixels outside
of the geometry | 1028 // Intersect and reverse difference require modifying pixels outside
of the geometry |
| 1061 // that is being "drawn". In both cases we erase all the pixels outs
ide of the geometry | 1029 // that is being "drawn". In both cases we erase all the pixels outs
ide of the geometry |
| 1062 // but leave the pixels inside the geometry alone. For reverse diffe
rence we invert all | 1030 // but leave the pixels inside the geometry alone. For reverse diffe
rence we invert all |
| 1063 // the pixels before clearing the ones outside the geometry. | 1031 // the pixels before clearing the ones outside the geometry. |
| 1064 if (SkRegion::kReverseDifference_Op == op) { | 1032 if (SkRegion::kReverseDifference_Op == op) { |
| 1065 SkRect temp = SkRect::Make(clipSpaceIBounds); | 1033 SkRect temp = SkRect::Make(clipSpaceIBounds); |
| 1066 // invert the entire scene | 1034 // invert the entire scene |
| 1067 helper.draw(temp, SkRegion::kXOR_Op, false, 0xFF); | 1035 helper.draw(temp, SkRegion::kXOR_Op, false, 0xFF); |
| 1068 } | 1036 } |
| 1069 | |
| 1070 SkPath clipPath; | 1037 SkPath clipPath; |
| 1071 element->asPath(&clipPath); | 1038 element->asPath(&clipPath); |
| 1072 clipPath.toggleInverseFillType(); | 1039 clipPath.toggleInverseFillType(); |
| 1073 helper.draw(clipPath, stroke, SkRegion::kReplace_Op, element->isAA()
, 0x00); | 1040 helper.draw(clipPath, stroke, SkRegion::kReplace_Op, element->isAA()
, 0x00); |
| 1074 | |
| 1075 continue; | 1041 continue; |
| 1076 } | 1042 } |
| 1077 | 1043 |
| 1078 // The other ops (union, xor, diff) only affect pixels inside | 1044 // The other ops (union, xor, diff) only affect pixels inside |
| 1079 // the geometry so they can just be drawn normally | 1045 // the geometry so they can just be drawn normally |
| 1080 if (Element::kRect_Type == element->getType()) { | 1046 if (Element::kRect_Type == element->getType()) { |
| 1081 helper.draw(element->getRect(), op, element->isAA(), 0xFF); | 1047 helper.draw(element->getRect(), op, element->isAA(), 0xFF); |
| 1082 } else { | 1048 } else { |
| 1083 SkPath path; | 1049 SkPath path; |
| 1084 element->asPath(&path); | 1050 element->asPath(&path); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1101 //////////////////////////////////////////////////////////////////////////////// | 1067 //////////////////////////////////////////////////////////////////////////////// |
| 1102 void GrClipMaskManager::purgeResources() { | 1068 void GrClipMaskManager::purgeResources() { |
| 1103 fAACache.purgeResources(); | 1069 fAACache.purgeResources(); |
| 1104 } | 1070 } |
| 1105 | 1071 |
| 1106 void GrClipMaskManager::setClipTarget(GrClipTarget* clipTarget) { | 1072 void GrClipMaskManager::setClipTarget(GrClipTarget* clipTarget) { |
| 1107 fClipTarget = clipTarget; | 1073 fClipTarget = clipTarget; |
| 1108 fAACache.setContext(clipTarget->getContext()); | 1074 fAACache.setContext(clipTarget->getContext()); |
| 1109 } | 1075 } |
| 1110 | 1076 |
| 1111 void GrClipMaskManager::adjustPathStencilParams(GrStencilSettings* settings) { | 1077 void GrClipMaskManager::adjustPathStencilParams(const GrStencilBuffer* stencilBu
ffer, |
| 1112 const GrDrawState& drawState = fClipTarget->getDrawState(); | 1078 GrStencilSettings* settings) { |
| 1113 | |
| 1114 // TODO: dynamically attach a stencil buffer | 1079 // TODO: dynamically attach a stencil buffer |
| 1115 int stencilBits = 0; | |
| 1116 GrStencilBuffer* stencilBuffer = drawState.getRenderTarget()->getStencilBuff
er(); | |
| 1117 if (stencilBuffer) { | 1080 if (stencilBuffer) { |
| 1118 stencilBits = stencilBuffer->bits(); | 1081 int stencilBits = stencilBuffer->bits(); |
| 1119 this->adjustStencilParams(settings, fClipMode, stencilBits); | 1082 this->adjustStencilParams(settings, fClipMode, stencilBits); |
| 1120 } | 1083 } |
| 1121 } | 1084 } |
| OLD | NEW |