| OLD | NEW |
| 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 "GrClipMaskManager.h" | 8 #include "GrClipMaskManager.h" |
| 9 #include "GrAAConvexPathRenderer.h" | 9 #include "GrAAConvexPathRenderer.h" |
| 10 #include "GrAAHairLinePathRenderer.h" | 10 #include "GrAAHairLinePathRenderer.h" |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 #include "effects/GrTextureDomain.h" | 24 #include "effects/GrTextureDomain.h" |
| 25 | 25 |
| 26 #define GR_AA_CLIP 1 | 26 #define GR_AA_CLIP 1 |
| 27 typedef SkClipStack::Element Element; | 27 typedef SkClipStack::Element Element; |
| 28 | 28 |
| 29 //////////////////////////////////////////////////////////////////////////////// | 29 //////////////////////////////////////////////////////////////////////////////// |
| 30 namespace { | 30 namespace { |
| 31 // set up the draw state to enable the aa clipping mask. Besides setting up the | 31 // set up the draw state to enable the aa clipping mask. Besides setting up the |
| 32 // stage matrix this also alters the vertex layout | 32 // stage matrix this also alters the vertex layout |
| 33 void setup_drawstate_aaclip(const SkIRect &devBound, | 33 void setup_drawstate_aaclip(const SkIRect &devBound, |
| 34 GrDrawState* drawState, | 34 GrPipelineBuilder* pipelineBuilder, |
| 35 GrTexture* result) { | 35 GrTexture* result) { |
| 36 SkASSERT(drawState); | 36 SkASSERT(pipelineBuilder); |
| 37 | 37 |
| 38 SkMatrix mat; | 38 SkMatrix mat; |
| 39 // We use device coords to compute the texture coordinates. We set our matri
x to be a | 39 // We use device coords to compute the texture coordinates. We set our matri
x to be a |
| 40 // translation to the devBound, and then a scaling matrix to normalized coor
ds. | 40 // translation to the devBound, and then a scaling matrix to normalized coor
ds. |
| 41 mat.setIDiv(result->width(), result->height()); | 41 mat.setIDiv(result->width(), result->height()); |
| 42 mat.preTranslate(SkIntToScalar(-devBound.fLeft), | 42 mat.preTranslate(SkIntToScalar(-devBound.fLeft), |
| 43 SkIntToScalar(-devBound.fTop)); | 43 SkIntToScalar(-devBound.fTop)); |
| 44 | 44 |
| 45 SkIRect domainTexels = SkIRect::MakeWH(devBound.width(), devBound.height()); | 45 SkIRect domainTexels = SkIRect::MakeWH(devBound.width(), devBound.height()); |
| 46 // This could be a long-lived effect that is cached with the alpha-mask. | 46 // This could be a long-lived effect that is cached with the alpha-mask. |
| 47 drawState->addCoverageProcessor( | 47 pipelineBuilder->addCoverageProcessor( |
| 48 GrTextureDomainEffect::Create(result, | 48 GrTextureDomainEffect::Create(result, |
| 49 mat, | 49 mat, |
| 50 GrTextureDomain::MakeTexelDomain(result, d
omainTexels), | 50 GrTextureDomain::MakeTexelDomain(result, d
omainTexels), |
| 51 GrTextureDomain::kDecal_Mode, | 51 GrTextureDomain::kDecal_Mode, |
| 52 GrTextureParams::kNone_FilterMode, | 52 GrTextureParams::kNone_FilterMode, |
| 53 kDevice_GrCoordSet))->unref(); | 53 kDevice_GrCoordSet))->unref(); |
| 54 } | 54 } |
| 55 | 55 |
| 56 bool path_needs_SW_renderer(GrContext* context, | 56 bool path_needs_SW_renderer(GrContext* context, |
| 57 const GrDrawTarget* gpu, | 57 const GrDrawTarget* gpu, |
| 58 const GrDrawState* drawState, | 58 const GrPipelineBuilder* pipelineBuilder, |
| 59 const SkMatrix& viewMatrix, | 59 const SkMatrix& viewMatrix, |
| 60 const SkPath& origPath, | 60 const SkPath& origPath, |
| 61 const SkStrokeRec& stroke, | 61 const SkStrokeRec& stroke, |
| 62 bool doAA) { | 62 bool doAA) { |
| 63 // 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 |
| 64 SkTCopyOnFirstWrite<SkPath> path(origPath); | 64 SkTCopyOnFirstWrite<SkPath> path(origPath); |
| 65 if (path->isInverseFillType()) { | 65 if (path->isInverseFillType()) { |
| 66 path.writable()->toggleInverseFillType(); | 66 path.writable()->toggleInverseFillType(); |
| 67 } | 67 } |
| 68 // last (false) parameter disallows use of the SW path renderer | 68 // last (false) parameter disallows use of the SW path renderer |
| 69 GrPathRendererChain::DrawType type = doAA ? | 69 GrPathRendererChain::DrawType type = doAA ? |
| 70 GrPathRendererChain::kColorAntiAlias_Dr
awType : | 70 GrPathRendererChain::kColorAntiAlias_Dr
awType : |
| 71 GrPathRendererChain::kColor_DrawType; | 71 GrPathRendererChain::kColor_DrawType; |
| 72 | 72 |
| 73 return NULL == context->getPathRenderer(gpu, drawState, viewMatrix, *path, s
troke, false, type); | 73 return NULL == context->getPathRenderer(gpu, pipelineBuilder, viewMatrix, *p
ath, stroke, |
| 74 false, type); |
| 74 } | 75 } |
| 75 } | 76 } |
| 76 | 77 |
| 77 /* | 78 /* |
| 78 * This method traverses the clip stack to see if the GrSoftwarePathRenderer | 79 * This method traverses the clip stack to see if the GrSoftwarePathRenderer |
| 79 * will be used on any element. If so, it returns true to indicate that the | 80 * will be used on any element. If so, it returns true to indicate that the |
| 80 * entire clip should be rendered in SW and then uploaded en masse to the gpu. | 81 * entire clip should be rendered in SW and then uploaded en masse to the gpu. |
| 81 */ | 82 */ |
| 82 bool GrClipMaskManager::useSWOnlyPath(const GrDrawState* drawState, | 83 bool GrClipMaskManager::useSWOnlyPath(const GrPipelineBuilder* pipelineBuilder, |
| 83 const SkVector& clipToMaskOffset, | 84 const SkVector& clipToMaskOffset, |
| 84 const GrReducedClip::ElementList& elements
) { | 85 const GrReducedClip::ElementList& elements
) { |
| 85 // TODO: generalize this function so that when | 86 // TODO: generalize this function so that when |
| 86 // a clip gets complex enough it can just be done in SW regardless | 87 // a clip gets complex enough it can just be done in SW regardless |
| 87 // of whether it would invoke the GrSoftwarePathRenderer. | 88 // of whether it would invoke the GrSoftwarePathRenderer. |
| 88 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); | 89 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); |
| 89 | 90 |
| 90 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip | 91 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip |
| 91 // space. | 92 // space. |
| 92 SkMatrix translate; | 93 SkMatrix translate; |
| 93 translate.setTranslate(clipToMaskOffset); | 94 translate.setTranslate(clipToMaskOffset); |
| 94 | 95 |
| 95 for (GrReducedClip::ElementList::Iter iter(elements.headIter()); iter.get();
iter.next()) { | 96 for (GrReducedClip::ElementList::Iter iter(elements.headIter()); iter.get();
iter.next()) { |
| 96 const Element* element = iter.get(); | 97 const Element* element = iter.get(); |
| 97 // rects can always be drawn directly w/o using the software path | 98 // rects can always be drawn directly w/o using the software path |
| 98 // Skip rrects once we're drawing them directly. | 99 // Skip rrects once we're drawing them directly. |
| 99 if (Element::kRect_Type != element->getType()) { | 100 if (Element::kRect_Type != element->getType()) { |
| 100 SkPath path; | 101 SkPath path; |
| 101 element->asPath(&path); | 102 element->asPath(&path); |
| 102 if (path_needs_SW_renderer(this->getContext(), fClipTarget, drawStat
e, translate, | 103 if (path_needs_SW_renderer(this->getContext(), fClipTarget, pipeline
Builder, translate, |
| 103 path, stroke, element->isAA())) { | 104 path, stroke, element->isAA())) { |
| 104 return true; | 105 return true; |
| 105 } | 106 } |
| 106 } | 107 } |
| 107 } | 108 } |
| 108 return false; | 109 return false; |
| 109 } | 110 } |
| 110 | 111 |
| 111 bool GrClipMaskManager::installClipEffects(GrDrawState* drawState, | 112 bool GrClipMaskManager::installClipEffects(GrPipelineBuilder* pipelineBuilder, |
| 112 GrDrawState::AutoRestoreEffects* are, | 113 GrPipelineBuilder::AutoRestoreEffects
* are, |
| 113 const GrReducedClip::ElementList& ele
ments, | 114 const GrReducedClip::ElementList& ele
ments, |
| 114 const SkVector& clipToRTOffset, | 115 const SkVector& clipToRTOffset, |
| 115 const SkRect* drawBounds) { | 116 const SkRect* drawBounds) { |
| 116 SkRect boundsInClipSpace; | 117 SkRect boundsInClipSpace; |
| 117 if (drawBounds) { | 118 if (drawBounds) { |
| 118 boundsInClipSpace = *drawBounds; | 119 boundsInClipSpace = *drawBounds; |
| 119 boundsInClipSpace.offset(-clipToRTOffset.fX, -clipToRTOffset.fY); | 120 boundsInClipSpace.offset(-clipToRTOffset.fX, -clipToRTOffset.fY); |
| 120 } | 121 } |
| 121 | 122 |
| 122 are->set(drawState); | 123 are->set(pipelineBuilder); |
| 123 GrRenderTarget* rt = drawState->getRenderTarget(); | 124 GrRenderTarget* rt = pipelineBuilder->getRenderTarget(); |
| 124 GrReducedClip::ElementList::Iter iter(elements); | 125 GrReducedClip::ElementList::Iter iter(elements); |
| 125 bool failed = false; | 126 bool failed = false; |
| 126 while (iter.get()) { | 127 while (iter.get()) { |
| 127 SkRegion::Op op = iter.get()->getOp(); | 128 SkRegion::Op op = iter.get()->getOp(); |
| 128 bool invert; | 129 bool invert; |
| 129 bool skip = false; | 130 bool skip = false; |
| 130 switch (op) { | 131 switch (op) { |
| 131 case SkRegion::kReplace_Op: | 132 case SkRegion::kReplace_Op: |
| 132 SkASSERT(iter.get() == elements.head()); | 133 SkASSERT(iter.get() == elements.head()); |
| 133 // Fallthrough, handled same as intersect. | 134 // Fallthrough, handled same as intersect. |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 179 case SkClipStack::Element::kRect_Type: { | 180 case SkClipStack::Element::kRect_Type: { |
| 180 SkRect rect = iter.get()->getRect(); | 181 SkRect rect = iter.get()->getRect(); |
| 181 rect.offset(clipToRTOffset.fX, clipToRTOffset.fY); | 182 rect.offset(clipToRTOffset.fX, clipToRTOffset.fY); |
| 182 fp.reset(GrConvexPolyEffect::Create(edgeType, rect)); | 183 fp.reset(GrConvexPolyEffect::Create(edgeType, rect)); |
| 183 break; | 184 break; |
| 184 } | 185 } |
| 185 default: | 186 default: |
| 186 break; | 187 break; |
| 187 } | 188 } |
| 188 if (fp) { | 189 if (fp) { |
| 189 drawState->addCoverageProcessor(fp); | 190 pipelineBuilder->addCoverageProcessor(fp); |
| 190 } else { | 191 } else { |
| 191 failed = true; | 192 failed = true; |
| 192 break; | 193 break; |
| 193 } | 194 } |
| 194 } | 195 } |
| 195 iter.next(); | 196 iter.next(); |
| 196 } | 197 } |
| 197 | 198 |
| 198 if (failed) { | 199 if (failed) { |
| 199 are->set(NULL); | 200 are->set(NULL); |
| 200 } | 201 } |
| 201 return !failed; | 202 return !failed; |
| 202 } | 203 } |
| 203 | 204 |
| 204 //////////////////////////////////////////////////////////////////////////////// | 205 //////////////////////////////////////////////////////////////////////////////// |
| 205 // sort out what kind of clip mask needs to be created: alpha, stencil, | 206 // sort out what kind of clip mask needs to be created: alpha, stencil, |
| 206 // scissor, or entirely software | 207 // scissor, or entirely software |
| 207 bool GrClipMaskManager::setupClipping(GrDrawState* drawState, | 208 bool GrClipMaskManager::setupClipping(GrPipelineBuilder* pipelineBuilder, |
| 208 GrDrawState::AutoRestoreEffects* are, | 209 GrPipelineBuilder::AutoRestoreEffects* are
, |
| 209 GrDrawState::AutoRestoreStencil* ars, | 210 GrPipelineBuilder::AutoRestoreStencil* ars
, |
| 210 GrScissorState* scissorState, | 211 GrScissorState* scissorState, |
| 211 const GrClipData* clipDataIn, | 212 const GrClipData* clipDataIn, |
| 212 const SkRect* devBounds) { | 213 const SkRect* devBounds) { |
| 213 fCurrClipMaskType = kNone_ClipMaskType; | 214 fCurrClipMaskType = kNone_ClipMaskType; |
| 214 if (kRespectClip_StencilClipMode == fClipMode) { | 215 if (kRespectClip_StencilClipMode == fClipMode) { |
| 215 fClipMode = kIgnoreClip_StencilClipMode; | 216 fClipMode = kIgnoreClip_StencilClipMode; |
| 216 } | 217 } |
| 217 | 218 |
| 218 GrReducedClip::ElementList elements(16); | 219 GrReducedClip::ElementList elements(16); |
| 219 int32_t genID; | 220 int32_t genID; |
| 220 GrReducedClip::InitialState initialState; | 221 GrReducedClip::InitialState initialState; |
| 221 SkIRect clipSpaceIBounds; | 222 SkIRect clipSpaceIBounds; |
| 222 bool requiresAA; | 223 bool requiresAA; |
| 223 GrRenderTarget* rt = drawState->getRenderTarget(); | 224 GrRenderTarget* rt = pipelineBuilder->getRenderTarget(); |
| 224 | 225 |
| 225 // GrDrawTarget should have filtered this for us | 226 // GrDrawTarget should have filtered this for us |
| 226 SkASSERT(rt); | 227 SkASSERT(rt); |
| 227 | 228 |
| 228 bool ignoreClip = !drawState->isClipState() || clipDataIn->fClipStack->isWid
eOpen(); | 229 bool ignoreClip = !pipelineBuilder->isClipState() || clipDataIn->fClipStack-
>isWideOpen(); |
| 229 if (!ignoreClip) { | 230 if (!ignoreClip) { |
| 230 SkIRect clipSpaceRTIBounds = SkIRect::MakeWH(rt->width(), rt->height()); | 231 SkIRect clipSpaceRTIBounds = SkIRect::MakeWH(rt->width(), rt->height()); |
| 231 clipSpaceRTIBounds.offset(clipDataIn->fOrigin); | 232 clipSpaceRTIBounds.offset(clipDataIn->fOrigin); |
| 232 GrReducedClip::ReduceClipStack(*clipDataIn->fClipStack, | 233 GrReducedClip::ReduceClipStack(*clipDataIn->fClipStack, |
| 233 clipSpaceRTIBounds, | 234 clipSpaceRTIBounds, |
| 234 &elements, | 235 &elements, |
| 235 &genID, | 236 &genID, |
| 236 &initialState, | 237 &initialState, |
| 237 &clipSpaceIBounds, | 238 &clipSpaceIBounds, |
| 238 &requiresAA); | 239 &requiresAA); |
| 239 if (elements.isEmpty()) { | 240 if (elements.isEmpty()) { |
| 240 if (GrReducedClip::kAllIn_InitialState == initialState) { | 241 if (GrReducedClip::kAllIn_InitialState == initialState) { |
| 241 ignoreClip = clipSpaceIBounds == clipSpaceRTIBounds; | 242 ignoreClip = clipSpaceIBounds == clipSpaceRTIBounds; |
| 242 } else { | 243 } else { |
| 243 return false; | 244 return false; |
| 244 } | 245 } |
| 245 } | 246 } |
| 246 } | 247 } |
| 247 | 248 |
| 248 if (ignoreClip) { | 249 if (ignoreClip) { |
| 249 this->setDrawStateStencil(drawState, ars); | 250 this->setPipelineBuilderStencil(pipelineBuilder, ars); |
| 250 return true; | 251 return true; |
| 251 } | 252 } |
| 252 | 253 |
| 253 // An element count of 4 was chosen because of the common pattern in Blink o
f: | 254 // An element count of 4 was chosen because of the common pattern in Blink o
f: |
| 254 // isect RR | 255 // isect RR |
| 255 // diff RR | 256 // diff RR |
| 256 // isect convex_poly | 257 // isect convex_poly |
| 257 // isect convex_poly | 258 // isect convex_poly |
| 258 // when drawing rounded div borders. This could probably be tuned based on a | 259 // when drawing rounded div borders. This could probably be tuned based on a |
| 259 // configuration's relative costs of switching RTs to generate a mask vs | 260 // configuration's relative costs of switching RTs to generate a mask vs |
| 260 // longer shaders. | 261 // longer shaders. |
| 261 if (elements.count() <= 4) { | 262 if (elements.count() <= 4) { |
| 262 SkVector clipToRTOffset = { SkIntToScalar(-clipDataIn->fOrigin.fX), | 263 SkVector clipToRTOffset = { SkIntToScalar(-clipDataIn->fOrigin.fX), |
| 263 SkIntToScalar(-clipDataIn->fOrigin.fY) }; | 264 SkIntToScalar(-clipDataIn->fOrigin.fY) }; |
| 264 if (elements.isEmpty() || | 265 if (elements.isEmpty() || |
| 265 (requiresAA && this->installClipEffects(drawState, are, elements, cl
ipToRTOffset, | 266 (requiresAA && this->installClipEffects(pipelineBuilder, are, elemen
ts, clipToRTOffset, |
| 266 devBounds))) { | 267 devBounds))) { |
| 267 SkIRect scissorSpaceIBounds(clipSpaceIBounds); | 268 SkIRect scissorSpaceIBounds(clipSpaceIBounds); |
| 268 scissorSpaceIBounds.offset(-clipDataIn->fOrigin); | 269 scissorSpaceIBounds.offset(-clipDataIn->fOrigin); |
| 269 if (NULL == devBounds || | 270 if (NULL == devBounds || |
| 270 !SkRect::Make(scissorSpaceIBounds).contains(*devBounds)) { | 271 !SkRect::Make(scissorSpaceIBounds).contains(*devBounds)) { |
| 271 scissorState->set(scissorSpaceIBounds); | 272 scissorState->set(scissorSpaceIBounds); |
| 272 } | 273 } |
| 273 this->setDrawStateStencil(drawState, ars); | 274 this->setPipelineBuilderStencil(pipelineBuilder, ars); |
| 274 return true; | 275 return true; |
| 275 } | 276 } |
| 276 } | 277 } |
| 277 | 278 |
| 278 #if GR_AA_CLIP | 279 #if GR_AA_CLIP |
| 279 // If MSAA is enabled we can do everything in the stencil buffer. | 280 // If MSAA is enabled we can do everything in the stencil buffer. |
| 280 if (0 == rt->numSamples() && requiresAA) { | 281 if (0 == rt->numSamples() && requiresAA) { |
| 281 GrTexture* result = NULL; | 282 GrTexture* result = NULL; |
| 282 | 283 |
| 283 // The top-left of the mask corresponds to the top-left corner of the bo
unds. | 284 // The top-left of the mask corresponds to the top-left corner of the bo
unds. |
| 284 SkVector clipToMaskOffset = { | 285 SkVector clipToMaskOffset = { |
| 285 SkIntToScalar(-clipSpaceIBounds.fLeft), | 286 SkIntToScalar(-clipSpaceIBounds.fLeft), |
| 286 SkIntToScalar(-clipSpaceIBounds.fTop) | 287 SkIntToScalar(-clipSpaceIBounds.fTop) |
| 287 }; | 288 }; |
| 288 | 289 |
| 289 if (this->useSWOnlyPath(drawState, clipToMaskOffset, elements)) { | 290 if (this->useSWOnlyPath(pipelineBuilder, clipToMaskOffset, elements)) { |
| 290 // The clip geometry is complex enough that it will be more efficien
t to create it | 291 // The clip geometry is complex enough that it will be more efficien
t to create it |
| 291 // entirely in software | 292 // entirely in software |
| 292 result = this->createSoftwareClipMask(genID, | 293 result = this->createSoftwareClipMask(genID, |
| 293 initialState, | 294 initialState, |
| 294 elements, | 295 elements, |
| 295 clipToMaskOffset, | 296 clipToMaskOffset, |
| 296 clipSpaceIBounds); | 297 clipSpaceIBounds); |
| 297 } else { | 298 } else { |
| 298 result = this->createAlphaClipMask(genID, | 299 result = this->createAlphaClipMask(genID, |
| 299 initialState, | 300 initialState, |
| 300 elements, | 301 elements, |
| 301 clipToMaskOffset, | 302 clipToMaskOffset, |
| 302 clipSpaceIBounds); | 303 clipSpaceIBounds); |
| 303 } | 304 } |
| 304 | 305 |
| 305 if (result) { | 306 if (result) { |
| 306 // The mask's top left coord should be pinned to the rounded-out top
left corner of | 307 // The mask's top left coord should be pinned to the rounded-out top
left corner of |
| 307 // clipSpace bounds. We determine the mask's position WRT to the ren
der target here. | 308 // clipSpace bounds. We determine the mask's position WRT to the ren
der target here. |
| 308 SkIRect rtSpaceMaskBounds = clipSpaceIBounds; | 309 SkIRect rtSpaceMaskBounds = clipSpaceIBounds; |
| 309 rtSpaceMaskBounds.offset(-clipDataIn->fOrigin); | 310 rtSpaceMaskBounds.offset(-clipDataIn->fOrigin); |
| 310 setup_drawstate_aaclip(rtSpaceMaskBounds, drawState, result); | 311 setup_drawstate_aaclip(rtSpaceMaskBounds, pipelineBuilder, result); |
| 311 this->setDrawStateStencil(drawState, ars); | 312 this->setPipelineBuilderStencil(pipelineBuilder, ars); |
| 312 return true; | 313 return true; |
| 313 } | 314 } |
| 314 // if alpha clip mask creation fails fall through to the non-AA code pat
hs | 315 // if alpha clip mask creation fails fall through to the non-AA code pat
hs |
| 315 } | 316 } |
| 316 #endif // GR_AA_CLIP | 317 #endif // GR_AA_CLIP |
| 317 | 318 |
| 318 // Either a hard (stencil buffer) clip was explicitly requested or an anti-a
liased clip couldn't | 319 // Either a hard (stencil buffer) clip was explicitly requested or an anti-a
liased clip couldn't |
| 319 // be created. In either case, free up the texture in the anti-aliased mask
cache. | 320 // be created. In either case, free up the texture in the anti-aliased mask
cache. |
| 320 // TODO: this may require more investigation. Ganesh performs a lot of utili
ty draws (e.g., | 321 // TODO: this may require more investigation. Ganesh performs a lot of utili
ty draws (e.g., |
| 321 // clears, InOrderDrawBuffer playbacks) that hit the stencil buffer path. Th
ese may be | 322 // clears, InOrderDrawBuffer playbacks) that hit the stencil buffer path. Th
ese may be |
| 322 // "incorrectly" clearing the AA cache. | 323 // "incorrectly" clearing the AA cache. |
| 323 fAACache.reset(); | 324 fAACache.reset(); |
| 324 | 325 |
| 325 // use the stencil clip if we can't represent the clip as a rectangle. | 326 // use the stencil clip if we can't represent the clip as a rectangle. |
| 326 SkIPoint clipSpaceToStencilSpaceOffset = -clipDataIn->fOrigin; | 327 SkIPoint clipSpaceToStencilSpaceOffset = -clipDataIn->fOrigin; |
| 327 this->createStencilClipMask(rt, | 328 this->createStencilClipMask(rt, |
| 328 genID, | 329 genID, |
| 329 initialState, | 330 initialState, |
| 330 elements, | 331 elements, |
| 331 clipSpaceIBounds, | 332 clipSpaceIBounds, |
| 332 clipSpaceToStencilSpaceOffset); | 333 clipSpaceToStencilSpaceOffset); |
| 333 | 334 |
| 334 // This must occur after createStencilClipMask. That function may change the
scissor. Also, it | 335 // This must occur after createStencilClipMask. That function may change the
scissor. Also, it |
| 335 // only guarantees that the stencil mask is correct within the bounds it was
passed, so we must | 336 // only guarantees that the stencil mask is correct within the bounds it was
passed, so we must |
| 336 // use both stencil and scissor test to the bounds for the final draw. | 337 // use both stencil and scissor test to the bounds for the final draw. |
| 337 SkIRect scissorSpaceIBounds(clipSpaceIBounds); | 338 SkIRect scissorSpaceIBounds(clipSpaceIBounds); |
| 338 scissorSpaceIBounds.offset(clipSpaceToStencilSpaceOffset); | 339 scissorSpaceIBounds.offset(clipSpaceToStencilSpaceOffset); |
| 339 scissorState->set(scissorSpaceIBounds); | 340 scissorState->set(scissorSpaceIBounds); |
| 340 this->setDrawStateStencil(drawState, ars); | 341 this->setPipelineBuilderStencil(pipelineBuilder, ars); |
| 341 return true; | 342 return true; |
| 342 } | 343 } |
| 343 | 344 |
| 344 namespace { | 345 namespace { |
| 345 //////////////////////////////////////////////////////////////////////////////// | 346 //////////////////////////////////////////////////////////////////////////////// |
| 346 // Set a coverage drawing XPF on the drawState for the given op and invertCovera
ge mode | 347 // Set a coverage drawing XPF on the pipelineBuilder for the given op and invert
Coverage mode |
| 347 void set_coverage_drawing_xpf(SkRegion::Op op, bool invertCoverage, GrDrawState*
drawState) { | 348 void set_coverage_drawing_xpf(SkRegion::Op op, bool invertCoverage, |
| 349 GrPipelineBuilder* pipelineBuilder) { |
| 348 SkASSERT(op <= SkRegion::kLastOp); | 350 SkASSERT(op <= SkRegion::kLastOp); |
| 349 drawState->setCoverageSetOpXPFactory(op, invertCoverage); | 351 pipelineBuilder->setCoverageSetOpXPFactory(op, invertCoverage); |
| 350 } | 352 } |
| 351 } | 353 } |
| 352 | 354 |
| 353 //////////////////////////////////////////////////////////////////////////////// | 355 //////////////////////////////////////////////////////////////////////////////// |
| 354 bool GrClipMaskManager::drawElement(GrDrawState* drawState, | 356 bool GrClipMaskManager::drawElement(GrPipelineBuilder* pipelineBuilder, |
| 355 const SkMatrix& viewMatrix, | 357 const SkMatrix& viewMatrix, |
| 356 GrTexture* target, | 358 GrTexture* target, |
| 357 const SkClipStack::Element* element, | 359 const SkClipStack::Element* element, |
| 358 GrPathRenderer* pr) { | 360 GrPathRenderer* pr) { |
| 359 GrDrawTarget::AutoGeometryPush agp(fClipTarget); | 361 GrDrawTarget::AutoGeometryPush agp(fClipTarget); |
| 360 | 362 |
| 361 drawState->setRenderTarget(target->asRenderTarget()); | 363 pipelineBuilder->setRenderTarget(target->asRenderTarget()); |
| 362 | 364 |
| 363 // The color we use to draw does not matter since we will always be using a
GrCoverageSetOpXP | 365 // The color we use to draw does not matter since we will always be using a
GrCoverageSetOpXP |
| 364 // which ignores color. | 366 // which ignores color. |
| 365 GrColor color = GrColor_WHITE; | 367 GrColor color = GrColor_WHITE; |
| 366 | 368 |
| 367 // TODO: Draw rrects directly here. | 369 // TODO: Draw rrects directly here. |
| 368 switch (element->getType()) { | 370 switch (element->getType()) { |
| 369 case Element::kEmpty_Type: | 371 case Element::kEmpty_Type: |
| 370 SkDEBUGFAIL("Should never get here with an empty element."); | 372 SkDEBUGFAIL("Should never get here with an empty element."); |
| 371 break; | 373 break; |
| 372 case Element::kRect_Type: | 374 case Element::kRect_Type: |
| 373 // TODO: Do rects directly to the accumulator using a aa-rect GrProc
essor that covers | 375 // TODO: Do rects directly to the accumulator using a aa-rect GrProc
essor that covers |
| 374 // the entire mask bounds and writes 0 outside the rect. | 376 // the entire mask bounds and writes 0 outside the rect. |
| 375 if (element->isAA()) { | 377 if (element->isAA()) { |
| 376 SkRect devRect = element->getRect(); | 378 SkRect devRect = element->getRect(); |
| 377 viewMatrix.mapRect(&devRect); | 379 viewMatrix.mapRect(&devRect); |
| 378 this->getContext()->getAARectRenderer()->fillAARect(fClipTarget, | 380 this->getContext()->getAARectRenderer()->fillAARect(fClipTarget, |
| 379 drawState, | 381 pipelineBuil
der, |
| 380 color, | 382 color, |
| 381 viewMatrix, | 383 viewMatrix, |
| 382 element->get
Rect(), | 384 element->get
Rect(), |
| 383 devRect); | 385 devRect); |
| 384 } else { | 386 } else { |
| 385 fClipTarget->drawSimpleRect(drawState, color, viewMatrix, elemen
t->getRect()); | 387 fClipTarget->drawSimpleRect(pipelineBuilder, color, viewMatrix,
element->getRect()); |
| 386 } | 388 } |
| 387 return true; | 389 return true; |
| 388 default: { | 390 default: { |
| 389 SkPath path; | 391 SkPath path; |
| 390 element->asPath(&path); | 392 element->asPath(&path); |
| 391 path.setIsVolatile(true); | 393 path.setIsVolatile(true); |
| 392 if (path.isInverseFillType()) { | 394 if (path.isInverseFillType()) { |
| 393 path.toggleInverseFillType(); | 395 path.toggleInverseFillType(); |
| 394 } | 396 } |
| 395 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); | 397 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); |
| 396 if (NULL == pr) { | 398 if (NULL == pr) { |
| 397 GrPathRendererChain::DrawType type; | 399 GrPathRendererChain::DrawType type; |
| 398 type = element->isAA() ? GrPathRendererChain::kColorAntiAlias_Dr
awType : | 400 type = element->isAA() ? GrPathRendererChain::kColorAntiAlias_Dr
awType : |
| 399 GrPathRendererChain::kColor_DrawType; | 401 GrPathRendererChain::kColor_DrawType; |
| 400 pr = this->getContext()->getPathRenderer(fClipTarget, drawState,
viewMatrix, path, | 402 pr = this->getContext()->getPathRenderer(fClipTarget, pipelineBu
ilder, viewMatrix, |
| 401 stroke, false, type); | 403 path, stroke, false, ty
pe); |
| 402 } | 404 } |
| 403 if (NULL == pr) { | 405 if (NULL == pr) { |
| 404 return false; | 406 return false; |
| 405 } | 407 } |
| 406 | 408 |
| 407 pr->drawPath(fClipTarget, drawState, color, viewMatrix, path, stroke
, element->isAA()); | 409 pr->drawPath(fClipTarget, pipelineBuilder, color, viewMatrix, path,
stroke, |
| 410 element->isAA()); |
| 408 break; | 411 break; |
| 409 } | 412 } |
| 410 } | 413 } |
| 411 return true; | 414 return true; |
| 412 } | 415 } |
| 413 | 416 |
| 414 bool GrClipMaskManager::canStencilAndDrawElement(GrDrawState* drawState, | 417 bool GrClipMaskManager::canStencilAndDrawElement(GrPipelineBuilder* pipelineBuil
der, |
| 415 GrTexture* target, | 418 GrTexture* target, |
| 416 GrPathRenderer** pr, | 419 GrPathRenderer** pr, |
| 417 const SkClipStack::Element* ele
ment) { | 420 const SkClipStack::Element* ele
ment) { |
| 418 drawState->setRenderTarget(target->asRenderTarget()); | 421 pipelineBuilder->setRenderTarget(target->asRenderTarget()); |
| 419 | 422 |
| 420 if (Element::kRect_Type == element->getType()) { | 423 if (Element::kRect_Type == element->getType()) { |
| 421 return true; | 424 return true; |
| 422 } else { | 425 } else { |
| 423 // We shouldn't get here with an empty clip element. | 426 // We shouldn't get here with an empty clip element. |
| 424 SkASSERT(Element::kEmpty_Type != element->getType()); | 427 SkASSERT(Element::kEmpty_Type != element->getType()); |
| 425 SkPath path; | 428 SkPath path; |
| 426 element->asPath(&path); | 429 element->asPath(&path); |
| 427 if (path.isInverseFillType()) { | 430 if (path.isInverseFillType()) { |
| 428 path.toggleInverseFillType(); | 431 path.toggleInverseFillType(); |
| 429 } | 432 } |
| 430 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); | 433 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); |
| 431 GrPathRendererChain::DrawType type = element->isAA() ? | 434 GrPathRendererChain::DrawType type = element->isAA() ? |
| 432 GrPathRendererChain::kStencilAndColorAntiAlias_DrawType : | 435 GrPathRendererChain::kStencilAndColorAntiAlias_DrawType : |
| 433 GrPathRendererChain::kStencilAndColor_DrawType; | 436 GrPathRendererChain::kStencilAndColor_DrawType; |
| 434 *pr = this->getContext()->getPathRenderer(fClipTarget, drawState, SkMatr
ix::I(), path, | 437 *pr = this->getContext()->getPathRenderer(fClipTarget, pipelineBuilder,
SkMatrix::I(), path, |
| 435 stroke, false, type); | 438 stroke, false, type); |
| 436 return SkToBool(*pr); | 439 return SkToBool(*pr); |
| 437 } | 440 } |
| 438 } | 441 } |
| 439 | 442 |
| 440 void GrClipMaskManager::mergeMask(GrDrawState* drawState, | 443 void GrClipMaskManager::mergeMask(GrPipelineBuilder* pipelineBuilder, |
| 441 GrTexture* dstMask, | 444 GrTexture* dstMask, |
| 442 GrTexture* srcMask, | 445 GrTexture* srcMask, |
| 443 SkRegion::Op op, | 446 SkRegion::Op op, |
| 444 const SkIRect& dstBound, | 447 const SkIRect& dstBound, |
| 445 const SkIRect& srcBound) { | 448 const SkIRect& srcBound) { |
| 446 drawState->setRenderTarget(dstMask->asRenderTarget()); | 449 pipelineBuilder->setRenderTarget(dstMask->asRenderTarget()); |
| 447 | 450 |
| 448 // We want to invert the coverage here | 451 // We want to invert the coverage here |
| 449 set_coverage_drawing_xpf(op, false, drawState); | 452 set_coverage_drawing_xpf(op, false, pipelineBuilder); |
| 450 | 453 |
| 451 SkMatrix sampleM; | 454 SkMatrix sampleM; |
| 452 sampleM.setIDiv(srcMask->width(), srcMask->height()); | 455 sampleM.setIDiv(srcMask->width(), srcMask->height()); |
| 453 | 456 |
| 454 drawState->addCoverageProcessor( | 457 pipelineBuilder->addCoverageProcessor( |
| 455 GrTextureDomainEffect::Create(srcMask, | 458 GrTextureDomainEffect::Create(srcMask, |
| 456 sampleM, | 459 sampleM, |
| 457 GrTextureDomain::MakeTexelDomain(srcMask,
srcBound), | 460 GrTextureDomain::MakeTexelDomain(srcMask,
srcBound), |
| 458 GrTextureDomain::kDecal_Mode, | 461 GrTextureDomain::kDecal_Mode, |
| 459 GrTextureParams::kNone_FilterMode))->unref
(); | 462 GrTextureParams::kNone_FilterMode))->unref
(); |
| 460 // The color passed in here does not matter since the coverageSetOpXP won't
read it. | 463 // The color passed in here does not matter since the coverageSetOpXP won't
read it. |
| 461 fClipTarget->drawSimpleRect(drawState, GrColor_WHITE, SkMatrix::I(), SkRect:
:Make(dstBound)); | 464 fClipTarget->drawSimpleRect(pipelineBuilder, GrColor_WHITE, SkMatrix::I(), |
| 465 SkRect::Make(dstBound)); |
| 462 } | 466 } |
| 463 | 467 |
| 464 GrTexture* GrClipMaskManager::createTempMask(int width, int height) { | 468 GrTexture* GrClipMaskManager::createTempMask(int width, int height) { |
| 465 GrSurfaceDesc desc; | 469 GrSurfaceDesc desc; |
| 466 desc.fFlags = kRenderTarget_GrSurfaceFlag; | 470 desc.fFlags = kRenderTarget_GrSurfaceFlag; |
| 467 desc.fWidth = width; | 471 desc.fWidth = width; |
| 468 desc.fHeight = height; | 472 desc.fHeight = height; |
| 469 if (this->getContext()->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) { | 473 if (this->getContext()->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) { |
| 470 desc.fConfig = kAlpha_8_GrPixelConfig; | 474 desc.fConfig = kAlpha_8_GrPixelConfig; |
| 471 } else { | 475 } else { |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 556 // cleared. | 560 // cleared. |
| 557 GrDrawTarget::AutoClipRestore acr(fClipTarget, maskSpaceIBounds); | 561 GrDrawTarget::AutoClipRestore acr(fClipTarget, maskSpaceIBounds); |
| 558 SkAutoTUnref<GrTexture> temp; | 562 SkAutoTUnref<GrTexture> temp; |
| 559 | 563 |
| 560 // walk through each clip element and perform its set op | 564 // walk through each clip element and perform its set op |
| 561 for (GrReducedClip::ElementList::Iter iter = elements.headIter(); iter.get()
; iter.next()) { | 565 for (GrReducedClip::ElementList::Iter iter = elements.headIter(); iter.get()
; iter.next()) { |
| 562 const Element* element = iter.get(); | 566 const Element* element = iter.get(); |
| 563 SkRegion::Op op = element->getOp(); | 567 SkRegion::Op op = element->getOp(); |
| 564 bool invert = element->isInverseFilled(); | 568 bool invert = element->isInverseFilled(); |
| 565 if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDiffere
nce_Op == op) { | 569 if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDiffere
nce_Op == op) { |
| 566 GrDrawState drawState; | 570 GrPipelineBuilder pipelineBuilder; |
| 567 drawState.enableState(GrDrawState::kClip_StateBit); | 571 pipelineBuilder.enableState(GrPipelineBuilder::kClip_StateBit); |
| 568 | 572 |
| 569 GrPathRenderer* pr = NULL; | 573 GrPathRenderer* pr = NULL; |
| 570 bool useTemp = !this->canStencilAndDrawElement(&drawState, result, &
pr, element); | 574 bool useTemp = !this->canStencilAndDrawElement(&pipelineBuilder, res
ult, &pr, element); |
| 571 GrTexture* dst; | 575 GrTexture* dst; |
| 572 // This is the bounds of the clip element in the space of the alpha-
mask. The temporary | 576 // This is the bounds of the clip element in the space of the alpha-
mask. The temporary |
| 573 // mask buffer can be substantially larger than the actually clip st
ack element. We | 577 // mask buffer can be substantially larger than the actually clip st
ack element. We |
| 574 // touch the minimum number of pixels necessary and use decal mode t
o combine it with | 578 // touch the minimum number of pixels necessary and use decal mode t
o combine it with |
| 575 // the accumulator. | 579 // the accumulator. |
| 576 SkIRect maskSpaceElementIBounds; | 580 SkIRect maskSpaceElementIBounds; |
| 577 | 581 |
| 578 if (useTemp) { | 582 if (useTemp) { |
| 579 if (invert) { | 583 if (invert) { |
| 580 maskSpaceElementIBounds = maskSpaceIBounds; | 584 maskSpaceElementIBounds = maskSpaceIBounds; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 591 fAACache.reset(); | 595 fAACache.reset(); |
| 592 return NULL; | 596 return NULL; |
| 593 } | 597 } |
| 594 } | 598 } |
| 595 dst = temp; | 599 dst = temp; |
| 596 // clear the temp target and set blend to replace | 600 // clear the temp target and set blend to replace |
| 597 fClipTarget->clear(&maskSpaceElementIBounds, | 601 fClipTarget->clear(&maskSpaceElementIBounds, |
| 598 invert ? 0xffffffff : 0x00000000, | 602 invert ? 0xffffffff : 0x00000000, |
| 599 true, | 603 true, |
| 600 dst->asRenderTarget()); | 604 dst->asRenderTarget()); |
| 601 set_coverage_drawing_xpf(SkRegion::kReplace_Op, invert, &drawSta
te); | 605 set_coverage_drawing_xpf(SkRegion::kReplace_Op, invert, &pipelin
eBuilder); |
| 602 } else { | 606 } else { |
| 603 // draw directly into the result with the stencil set to make th
e pixels affected | 607 // draw directly into the result with the stencil set to make th
e pixels affected |
| 604 // by the clip shape be non-zero. | 608 // by the clip shape be non-zero. |
| 605 dst = result; | 609 dst = result; |
| 606 GR_STATIC_CONST_SAME_STENCIL(kStencilInElement, | 610 GR_STATIC_CONST_SAME_STENCIL(kStencilInElement, |
| 607 kReplace_StencilOp, | 611 kReplace_StencilOp, |
| 608 kReplace_StencilOp, | 612 kReplace_StencilOp, |
| 609 kAlways_StencilFunc, | 613 kAlways_StencilFunc, |
| 610 0xffff, | 614 0xffff, |
| 611 0xffff, | 615 0xffff, |
| 612 0xffff); | 616 0xffff); |
| 613 drawState.setStencil(kStencilInElement); | 617 pipelineBuilder.setStencil(kStencilInElement); |
| 614 set_coverage_drawing_xpf(op, invert, &drawState); | 618 set_coverage_drawing_xpf(op, invert, &pipelineBuilder); |
| 615 } | 619 } |
| 616 | 620 |
| 617 if (!this->drawElement(&drawState, translate, dst, element, pr)) { | 621 if (!this->drawElement(&pipelineBuilder, translate, dst, element, pr
)) { |
| 618 fAACache.reset(); | 622 fAACache.reset(); |
| 619 return NULL; | 623 return NULL; |
| 620 } | 624 } |
| 621 | 625 |
| 622 if (useTemp) { | 626 if (useTemp) { |
| 623 GrDrawState backgroundDrawState; | 627 GrPipelineBuilder backgroundPipelineBuilder; |
| 624 backgroundDrawState.enableState(GrDrawState::kClip_StateBit); | 628 backgroundPipelineBuilder.enableState(GrPipelineBuilder::kClip_S
tateBit); |
| 625 backgroundDrawState.setRenderTarget(result->asRenderTarget()); | 629 backgroundPipelineBuilder.setRenderTarget(result->asRenderTarget
()); |
| 626 | 630 |
| 627 // Now draw into the accumulator using the real operation and th
e temp buffer as a | 631 // Now draw into the accumulator using the real operation and th
e temp buffer as a |
| 628 // texture | 632 // texture |
| 629 this->mergeMask(&backgroundDrawState, | 633 this->mergeMask(&backgroundPipelineBuilder, |
| 630 result, | 634 result, |
| 631 temp, | 635 temp, |
| 632 op, | 636 op, |
| 633 maskSpaceIBounds, | 637 maskSpaceIBounds, |
| 634 maskSpaceElementIBounds); | 638 maskSpaceElementIBounds); |
| 635 } else { | 639 } else { |
| 636 GrDrawState backgroundDrawState; | 640 GrPipelineBuilder backgroundPipelineBuilder; |
| 637 backgroundDrawState.enableState(GrDrawState::kClip_StateBit); | 641 backgroundPipelineBuilder.enableState(GrPipelineBuilder::kClip_S
tateBit); |
| 638 backgroundDrawState.setRenderTarget(result->asRenderTarget()); | 642 backgroundPipelineBuilder.setRenderTarget(result->asRenderTarget
()); |
| 639 | 643 |
| 640 set_coverage_drawing_xpf(op, !invert, &backgroundDrawState); | 644 set_coverage_drawing_xpf(op, !invert, &backgroundPipelineBuilder
); |
| 641 // Draw to the exterior pixels (those with a zero stencil value)
. | 645 // Draw to the exterior pixels (those with a zero stencil value)
. |
| 642 GR_STATIC_CONST_SAME_STENCIL(kDrawOutsideElement, | 646 GR_STATIC_CONST_SAME_STENCIL(kDrawOutsideElement, |
| 643 kZero_StencilOp, | 647 kZero_StencilOp, |
| 644 kZero_StencilOp, | 648 kZero_StencilOp, |
| 645 kEqual_StencilFunc, | 649 kEqual_StencilFunc, |
| 646 0xffff, | 650 0xffff, |
| 647 0x0000, | 651 0x0000, |
| 648 0xffff); | 652 0xffff); |
| 649 backgroundDrawState.setStencil(kDrawOutsideElement); | 653 backgroundPipelineBuilder.setStencil(kDrawOutsideElement); |
| 650 // The color passed in here does not matter since the coverageSe
tOpXP won't read it. | 654 // The color passed in here does not matter since the coverageSe
tOpXP won't read it. |
| 651 fClipTarget->drawSimpleRect(&backgroundDrawState, GrColor_WHITE,
translate, | 655 fClipTarget->drawSimpleRect(&backgroundPipelineBuilder, GrColor_
WHITE, translate, |
| 652 clipSpaceIBounds); | 656 clipSpaceIBounds); |
| 653 } | 657 } |
| 654 } else { | 658 } else { |
| 655 GrDrawState drawState; | 659 GrPipelineBuilder pipelineBuilder; |
| 656 drawState.enableState(GrDrawState::kClip_StateBit); | 660 pipelineBuilder.enableState(GrPipelineBuilder::kClip_StateBit); |
| 657 | 661 |
| 658 // all the remaining ops can just be directly draw into the accumula
tion buffer | 662 // all the remaining ops can just be directly draw into the accumula
tion buffer |
| 659 set_coverage_drawing_xpf(op, false, &drawState); | 663 set_coverage_drawing_xpf(op, false, &pipelineBuilder); |
| 660 // The color passed in here does not matter since the coverageSetOpX
P won't read it. | 664 // The color passed in here does not matter since the coverageSetOpX
P won't read it. |
| 661 this->drawElement(&drawState, translate, result, element); | 665 this->drawElement(&pipelineBuilder, translate, result, element); |
| 662 } | 666 } |
| 663 } | 667 } |
| 664 | 668 |
| 665 fCurrClipMaskType = kAlpha_ClipMaskType; | 669 fCurrClipMaskType = kAlpha_ClipMaskType; |
| 666 return result; | 670 return result; |
| 667 } | 671 } |
| 668 | 672 |
| 669 //////////////////////////////////////////////////////////////////////////////// | 673 //////////////////////////////////////////////////////////////////////////////// |
| 670 // Create a 1-bit clip mask in the stencil buffer. 'devClipBounds' are in device | 674 // Create a 1-bit clip mask in the stencil buffer. 'devClipBounds' are in device |
| 671 // (as opposed to canvas) coordinates | 675 // (as opposed to canvas) coordinates |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 705 | 709 |
| 706 fClipTarget->clearStencilClip(stencilSpaceIBounds, | 710 fClipTarget->clearStencilClip(stencilSpaceIBounds, |
| 707 GrReducedClip::kAllIn_InitialState == init
ialState, | 711 GrReducedClip::kAllIn_InitialState == init
ialState, |
| 708 rt); | 712 rt); |
| 709 | 713 |
| 710 // walk through each clip element and perform its set op | 714 // walk through each clip element and perform its set op |
| 711 // with the existing clip. | 715 // with the existing clip. |
| 712 for (GrReducedClip::ElementList::Iter iter(elements.headIter()); iter.ge
t(); iter.next()) { | 716 for (GrReducedClip::ElementList::Iter iter(elements.headIter()); iter.ge
t(); iter.next()) { |
| 713 const Element* element = iter.get(); | 717 const Element* element = iter.get(); |
| 714 | 718 |
| 715 GrDrawState drawState; | 719 GrPipelineBuilder pipelineBuilder; |
| 716 drawState.setRenderTarget(rt); | 720 pipelineBuilder.setRenderTarget(rt); |
| 717 drawState.enableState(GrDrawState::kClip_StateBit); | 721 pipelineBuilder.enableState(GrPipelineBuilder::kClip_StateBit); |
| 718 | 722 |
| 719 drawState.setDisableColorXPFactory(); | 723 pipelineBuilder.setDisableColorXPFactory(); |
| 720 | 724 |
| 721 // if the target is MSAA then we want MSAA enabled when the clip is
soft | 725 // if the target is MSAA then we want MSAA enabled when the clip is
soft |
| 722 if (rt->isMultisampled()) { | 726 if (rt->isMultisampled()) { |
| 723 drawState.setState(GrDrawState::kHWAntialias_StateBit, element->
isAA()); | 727 pipelineBuilder.setState(GrPipelineBuilder::kHWAntialias_StateBi
t, element->isAA()); |
| 724 } | 728 } |
| 725 | 729 |
| 726 bool fillInverted = false; | 730 bool fillInverted = false; |
| 727 // enabled at bottom of loop | 731 // enabled at bottom of loop |
| 728 fClipMode = kIgnoreClip_StencilClipMode; | 732 fClipMode = kIgnoreClip_StencilClipMode; |
| 729 | 733 |
| 730 // This will be used to determine whether the clip shape can be rend
ered into the | 734 // This will be used to determine whether the clip shape can be rend
ered into the |
| 731 // stencil with arbitrary stencil settings. | 735 // stencil with arbitrary stencil settings. |
| 732 GrPathRenderer::StencilSupport stencilSupport; | 736 GrPathRenderer::StencilSupport stencilSupport; |
| 733 | 737 |
| 734 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); | 738 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); |
| 735 SkRegion::Op op = element->getOp(); | 739 SkRegion::Op op = element->getOp(); |
| 736 | 740 |
| 737 GrPathRenderer* pr = NULL; | 741 GrPathRenderer* pr = NULL; |
| 738 SkPath clipPath; | 742 SkPath clipPath; |
| 739 if (Element::kRect_Type == element->getType()) { | 743 if (Element::kRect_Type == element->getType()) { |
| 740 stencilSupport = GrPathRenderer::kNoRestriction_StencilSupport; | 744 stencilSupport = GrPathRenderer::kNoRestriction_StencilSupport; |
| 741 fillInverted = false; | 745 fillInverted = false; |
| 742 } else { | 746 } else { |
| 743 element->asPath(&clipPath); | 747 element->asPath(&clipPath); |
| 744 fillInverted = clipPath.isInverseFillType(); | 748 fillInverted = clipPath.isInverseFillType(); |
| 745 if (fillInverted) { | 749 if (fillInverted) { |
| 746 clipPath.toggleInverseFillType(); | 750 clipPath.toggleInverseFillType(); |
| 747 } | 751 } |
| 748 pr = this->getContext()->getPathRenderer(fClipTarget, | 752 pr = this->getContext()->getPathRenderer(fClipTarget, |
| 749 &drawState, | 753 &pipelineBuilder, |
| 750 viewMatrix, | 754 viewMatrix, |
| 751 clipPath, | 755 clipPath, |
| 752 stroke, | 756 stroke, |
| 753 false, | 757 false, |
| 754 GrPathRendererChain::kS
tencilOnly_DrawType, | 758 GrPathRendererChain::kS
tencilOnly_DrawType, |
| 755 &stencilSupport); | 759 &stencilSupport); |
| 756 if (NULL == pr) { | 760 if (NULL == pr) { |
| 757 return false; | 761 return false; |
| 758 } | 762 } |
| 759 } | 763 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 777 // draw the element to the client stencil bits if necessary | 781 // draw the element to the client stencil bits if necessary |
| 778 if (!canDrawDirectToClip) { | 782 if (!canDrawDirectToClip) { |
| 779 GR_STATIC_CONST_SAME_STENCIL(gDrawToStencil, | 783 GR_STATIC_CONST_SAME_STENCIL(gDrawToStencil, |
| 780 kIncClamp_StencilOp, | 784 kIncClamp_StencilOp, |
| 781 kIncClamp_StencilOp, | 785 kIncClamp_StencilOp, |
| 782 kAlways_StencilFunc, | 786 kAlways_StencilFunc, |
| 783 0xffff, | 787 0xffff, |
| 784 0x0000, | 788 0x0000, |
| 785 0xffff); | 789 0xffff); |
| 786 if (Element::kRect_Type == element->getType()) { | 790 if (Element::kRect_Type == element->getType()) { |
| 787 *drawState.stencil() = gDrawToStencil; | 791 *pipelineBuilder.stencil() = gDrawToStencil; |
| 788 fClipTarget->drawSimpleRect(&drawState, GrColor_WHITE, viewM
atrix, | 792 fClipTarget->drawSimpleRect(&pipelineBuilder, GrColor_WHITE,
viewMatrix, |
| 789 element->getRect()); | 793 element->getRect()); |
| 790 } else { | 794 } else { |
| 791 if (!clipPath.isEmpty()) { | 795 if (!clipPath.isEmpty()) { |
| 792 GrDrawTarget::AutoGeometryPush agp(fClipTarget); | 796 GrDrawTarget::AutoGeometryPush agp(fClipTarget); |
| 793 if (canRenderDirectToStencil) { | 797 if (canRenderDirectToStencil) { |
| 794 *drawState.stencil() = gDrawToStencil; | 798 *pipelineBuilder.stencil() = gDrawToStencil; |
| 795 pr->drawPath(fClipTarget, &drawState, GrColor_WHITE,
viewMatrix, | 799 pr->drawPath(fClipTarget, &pipelineBuilder, GrColor_
WHITE, viewMatrix, |
| 796 clipPath, stroke, false); | 800 clipPath, stroke, false); |
| 797 } else { | 801 } else { |
| 798 pr->stencilPath(fClipTarget, &drawState, viewMatrix,
clipPath, stroke); | 802 pr->stencilPath(fClipTarget, &pipelineBuilder, viewM
atrix, clipPath, |
| 803 stroke); |
| 799 } | 804 } |
| 800 } | 805 } |
| 801 } | 806 } |
| 802 } | 807 } |
| 803 | 808 |
| 804 // now we modify the clip bit by rendering either the clip | 809 // now we modify the clip bit by rendering either the clip |
| 805 // element directly or a bounding rect of the entire clip. | 810 // element directly or a bounding rect of the entire clip. |
| 806 fClipMode = kModifyClip_StencilClipMode; | 811 fClipMode = kModifyClip_StencilClipMode; |
| 807 for (int p = 0; p < passes; ++p) { | 812 for (int p = 0; p < passes; ++p) { |
| 808 GrDrawState drawStateCopy(drawState); | 813 GrPipelineBuilder pipelineBuilderCopy(pipelineBuilder); |
| 809 *drawStateCopy.stencil() = stencilSettings[p]; | 814 *pipelineBuilderCopy.stencil() = stencilSettings[p]; |
| 810 | 815 |
| 811 if (canDrawDirectToClip) { | 816 if (canDrawDirectToClip) { |
| 812 if (Element::kRect_Type == element->getType()) { | 817 if (Element::kRect_Type == element->getType()) { |
| 813 fClipTarget->drawSimpleRect(&drawStateCopy, GrColor_WHIT
E, viewMatrix, | 818 fClipTarget->drawSimpleRect(&pipelineBuilderCopy, GrColo
r_WHITE, viewMatrix, |
| 814 element->getRect()); | 819 element->getRect()); |
| 815 } else { | 820 } else { |
| 816 GrDrawTarget::AutoGeometryPush agp(fClipTarget); | 821 GrDrawTarget::AutoGeometryPush agp(fClipTarget); |
| 817 pr->drawPath(fClipTarget, &drawStateCopy, GrColor_WHITE,
viewMatrix, | 822 pr->drawPath(fClipTarget, &pipelineBuilderCopy, GrColor_
WHITE, viewMatrix, |
| 818 clipPath, stroke, false); | 823 clipPath, stroke, false); |
| 819 } | 824 } |
| 820 } else { | 825 } else { |
| 821 // The view matrix is setup to do clip space -> stencil spac
e translation, so | 826 // The view matrix is setup to do clip space -> stencil spac
e translation, so |
| 822 // draw rect in clip space. | 827 // draw rect in clip space. |
| 823 fClipTarget->drawSimpleRect(&drawStateCopy, GrColor_WHITE, v
iewMatrix, | 828 fClipTarget->drawSimpleRect(&pipelineBuilderCopy, GrColor_WH
ITE, viewMatrix, |
| 824 SkRect::Make(clipSpaceIBounds)); | 829 SkRect::Make(clipSpaceIBounds)); |
| 825 } | 830 } |
| 826 } | 831 } |
| 827 } | 832 } |
| 828 } | 833 } |
| 829 // set this last because recursive draws may overwrite it back to kNone. | 834 // set this last because recursive draws may overwrite it back to kNone. |
| 830 SkASSERT(kNone_ClipMaskType == fCurrClipMaskType); | 835 SkASSERT(kNone_ClipMaskType == fCurrClipMaskType); |
| 831 fCurrClipMaskType = kStencil_ClipMaskType; | 836 fCurrClipMaskType = kStencil_ClipMaskType; |
| 832 fClipMode = kRespectClip_StencilClipMode; | 837 fClipMode = kRespectClip_StencilClipMode; |
| 833 return true; | 838 return true; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 878 kKeep_StencilOp, | 883 kKeep_StencilOp, |
| 879 kKeep_StencilOp, | 884 kKeep_StencilOp, |
| 880 kAlwaysIfInClip_StencilFunc, | 885 kAlwaysIfInClip_StencilFunc, |
| 881 0x0000, | 886 0x0000, |
| 882 0x0000, | 887 0x0000, |
| 883 0x0000); | 888 0x0000); |
| 884 return *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&gSettings); | 889 return *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&gSettings); |
| 885 } | 890 } |
| 886 } | 891 } |
| 887 | 892 |
| 888 void GrClipMaskManager::setDrawStateStencil(GrDrawState* drawState, | 893 void GrClipMaskManager::setPipelineBuilderStencil(GrPipelineBuilder* pipelineBui
lder, |
| 889 GrDrawState::AutoRestoreStencil* ars
) { | 894 GrPipelineBuilder::AutoRestore
Stencil* ars) { |
| 890 // We make two copies of the StencilSettings here (except in the early | 895 // We make two copies of the StencilSettings here (except in the early |
| 891 // exit scenario. One copy from draw state to the stack var. Then another | 896 // exit scenario. One copy from draw state to the stack var. Then another |
| 892 // from the stack var to the gpu. We could make this class hold a ptr to | 897 // from the stack var to the gpu. We could make this class hold a ptr to |
| 893 // GrGpu's fStencilSettings and eliminate the stack copy here. | 898 // GrGpu's fStencilSettings and eliminate the stack copy here. |
| 894 | 899 |
| 895 // use stencil for clipping if clipping is enabled and the clip | 900 // use stencil for clipping if clipping is enabled and the clip |
| 896 // has been written into the stencil. | 901 // has been written into the stencil. |
| 897 GrStencilSettings settings; | 902 GrStencilSettings settings; |
| 898 | 903 |
| 899 // The GrGpu client may not be using the stencil buffer but we may need to | 904 // The GrGpu client may not be using the stencil buffer but we may need to |
| 900 // enable it in order to respect a stencil clip. | 905 // enable it in order to respect a stencil clip. |
| 901 if (drawState->getStencil().isDisabled()) { | 906 if (pipelineBuilder->getStencil().isDisabled()) { |
| 902 if (GrClipMaskManager::kRespectClip_StencilClipMode == fClipMode) { | 907 if (GrClipMaskManager::kRespectClip_StencilClipMode == fClipMode) { |
| 903 settings = basic_apply_stencil_clip_settings(); | 908 settings = basic_apply_stencil_clip_settings(); |
| 904 } else { | 909 } else { |
| 905 return; | 910 return; |
| 906 } | 911 } |
| 907 } else { | 912 } else { |
| 908 settings = drawState->getStencil(); | 913 settings = pipelineBuilder->getStencil(); |
| 909 } | 914 } |
| 910 | 915 |
| 911 // TODO: dynamically attach a stencil buffer | 916 // TODO: dynamically attach a stencil buffer |
| 912 int stencilBits = 0; | 917 int stencilBits = 0; |
| 913 GrStencilBuffer* stencilBuffer = drawState->getRenderTarget()->getStencilBuf
fer(); | 918 GrStencilBuffer* stencilBuffer = pipelineBuilder->getRenderTarget()->getSten
cilBuffer(); |
| 914 if (stencilBuffer) { | 919 if (stencilBuffer) { |
| 915 stencilBits = stencilBuffer->bits(); | 920 stencilBits = stencilBuffer->bits(); |
| 916 } | 921 } |
| 917 | 922 |
| 918 SkASSERT(fClipTarget->caps()->stencilWrapOpsSupport() || !settings.usesWrapO
p()); | 923 SkASSERT(fClipTarget->caps()->stencilWrapOpsSupport() || !settings.usesWrapO
p()); |
| 919 SkASSERT(fClipTarget->caps()->twoSidedStencilSupport() || !settings.isTwoSid
ed()); | 924 SkASSERT(fClipTarget->caps()->twoSidedStencilSupport() || !settings.isTwoSid
ed()); |
| 920 this->adjustStencilParams(&settings, fClipMode, stencilBits); | 925 this->adjustStencilParams(&settings, fClipMode, stencilBits); |
| 921 ars->set(drawState); | 926 ars->set(pipelineBuilder); |
| 922 drawState->setStencil(settings); | 927 pipelineBuilder->setStencil(settings); |
| 923 } | 928 } |
| 924 | 929 |
| 925 void GrClipMaskManager::adjustStencilParams(GrStencilSettings* settings, | 930 void GrClipMaskManager::adjustStencilParams(GrStencilSettings* settings, |
| 926 StencilClipMode mode, | 931 StencilClipMode mode, |
| 927 int stencilBitCnt) { | 932 int stencilBitCnt) { |
| 928 SkASSERT(stencilBitCnt > 0); | 933 SkASSERT(stencilBitCnt > 0); |
| 929 | 934 |
| 930 if (kModifyClip_StencilClipMode == mode) { | 935 if (kModifyClip_StencilClipMode == mode) { |
| 931 // We assume that this clip manager itself is drawing to the GrGpu and | 936 // We assume that this clip manager itself is drawing to the GrGpu and |
| 932 // has already setup the correct values. | 937 // has already setup the correct values. |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1086 } | 1091 } |
| 1087 | 1092 |
| 1088 void GrClipMaskManager::adjustPathStencilParams(const GrStencilBuffer* stencilBu
ffer, | 1093 void GrClipMaskManager::adjustPathStencilParams(const GrStencilBuffer* stencilBu
ffer, |
| 1089 GrStencilSettings* settings) { | 1094 GrStencilSettings* settings) { |
| 1090 // TODO: dynamically attach a stencil buffer | 1095 // TODO: dynamically attach a stencil buffer |
| 1091 if (stencilBuffer) { | 1096 if (stencilBuffer) { |
| 1092 int stencilBits = stencilBuffer->bits(); | 1097 int stencilBits = stencilBuffer->bits(); |
| 1093 this->adjustStencilParams(settings, fClipMode, stencilBits); | 1098 this->adjustStencilParams(settings, fClipMode, stencilBits); |
| 1094 } | 1099 } |
| 1095 } | 1100 } |
| OLD | NEW |