1 2 /* 3 * Copyright 2012 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 #include "GrClipMaskManager.h" 10 #include "effects/GrTextureDomainEffect.h" 11 #include "GrGpu.h" 12 #include "GrRenderTarget.h" 13 #include "GrStencilBuffer.h" 14 #include "GrPathRenderer.h" 15 #include "GrPaint.h" 16 #include "SkRasterClip.h" 17 #include "SkStrokeRec.h" 18 #include "GrAAConvexPathRenderer.h" 19 #include "GrAAHairLinePathRenderer.h" 20 #include "GrSWMaskHelper.h" 21 22 #include "SkTLazy.h" 23 24 #define GR_AA_CLIP 1 25 26 typedef SkClipStack::Element Element; 27 28 using namespace GrReducedClip; 29 30 //////////////////////////////////////////////////////////////////////////////// 31 namespace { 32 // set up the draw state to enable the aa clipping mask. Besides setting up the 33 // stage matrix this also alters the vertex layout 34 void setup_drawstate_aaclip(GrGpu* gpu, 35 GrTexture* result, 36 const GrIRect &devBound) { 37 GrDrawState* drawState = gpu->drawState(); 38 GrAssert(drawState); 39 40 static const int kMaskStage = GrPaint::kTotalStages+1; 41 42 SkMatrix mat; 43 mat.setIDiv(result->width(), result->height()); 44 mat.preTranslate(SkIntToScalar(-devBound.fLeft), 45 SkIntToScalar(-devBound.fTop)); 46 mat.preConcat(drawState->getViewMatrix()); 47 48 SkIRect domainTexels = SkIRect::MakeWH(devBound.width(), devBound.height()); 49 // This could be a long-lived effect that is cached with the alpha-mask. 50 drawState->setEffect(kMaskStage, 51 GrTextureDomainEffect::Create(result, 52 mat, 53 GrTextureDomainEffect::MakeTexelDomain(result, domainTexels), 54 GrTextureDomainEffect::kDecal_WrapMode))->unref(); 55 } 56 57 bool path_needs_SW_renderer(GrContext* context, 58 GrGpu* gpu, 59 const SkPath& origPath, 60 const SkStrokeRec& stroke, 61 bool doAA) { 62 // the gpu alpha mask will draw the inverse paths as non-inverse to a temp buffer 63 SkTCopyOnFirstWrite<SkPath> path(origPath); 64 if (path->isInverseFillType()) { 65 path.writable()->toggleInverseFillType(); 66 } 67 // last (false) parameter disallows use of the SW path renderer 68 GrPathRendererChain::DrawType type = doAA ? 69 GrPathRendererChain::kColorAntiAlias_DrawType : 70 GrPathRendererChain::kColor_DrawType; 71 72 return NULL == context->getPathRenderer(*path, stroke, gpu, false, type); 73 } 74 75 } 76 77 /* 78 * 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 * entire clip should be rendered in SW and then uploaded en masse to the gpu. 81 */ 82 bool GrClipMaskManager::useSWOnlyPath(const ElementList& elements) { 83 84 // TODO: generalize this function so that when 85 // a clip gets complex enough it can just be done in SW regardless 86 // of whether it would invoke the GrSoftwarePathRenderer. 87 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); 88 89 for (ElementList::Iter iter(elements.headIter()); iter.get(); iter.next()) { 90 const Element* element = iter.get(); 91 // rects can always be drawn directly w/o using the software path 92 // so only paths need to be checked 93 if (Element::kPath_Type == element->getType() && 94 path_needs_SW_renderer(this->getContext(), fGpu, 95 element->getPath(), 96 stroke, 97 element->isAA())) { 98 return true; 99 } 100 } 101 return false; 102 } 103 104 //////////////////////////////////////////////////////////////////////////////// 105 // sort out what kind of clip mask needs to be created: alpha, stencil, 106 // scissor, or entirely software 107 bool GrClipMaskManager::setupClipping(const GrClipData* clipDataIn) { 108 fCurrClipMaskType = kNone_ClipMaskType; 109 110 ElementList elements(16); 111 InitialState initialState; 112 SkIRect clipSpaceIBounds; 113 bool requiresAA; 114 bool isRect = false; 115 116 GrDrawState* drawState = fGpu->drawState(); 117 118 const GrRenderTarget* rt = drawState->getRenderTarget(); 119 // GrDrawTarget should have filtered this for us 120 GrAssert(NULL != rt); 121 122 bool ignoreClip = !drawState->isClipState() || clipDataIn->fClipStack->isWideOpen(); 123 124 if (!ignoreClip) { 125 SkIRect clipSpaceRTIBounds = SkIRect::MakeWH(rt->width(), rt->height()); 126 clipSpaceRTIBounds.offset(clipDataIn->fOrigin); 127 ReduceClipStack(*clipDataIn->fClipStack, 128 clipSpaceRTIBounds, 129 &elements, 130 &initialState, 131 &clipSpaceIBounds, 132 &requiresAA); 133 if (elements.isEmpty()) { 134 if (kAllIn_InitialState == initialState) { 135 ignoreClip = clipSpaceIBounds == clipSpaceRTIBounds; 136 isRect = true; 137 } else { 138 return false; 139 } 140 } 141 } 142 143 if (ignoreClip) { 144 fGpu->disableScissor(); 145 this->setGpuStencil(); 146 return true; 147 } 148 149 #if GR_AA_CLIP 150 // TODO: catch isRect && requiresAA and use clip planes if available rather than a mask. 151 152 // If MSAA is enabled we can do everything in the stencil buffer. 153 if (0 == rt->numSamples() && requiresAA) { 154 int32_t genID = clipDataIn->fClipStack->getTopmostGenID(); 155 GrTexture* result = NULL; 156 157 if (this->useSWOnlyPath(elements)) { 158 // The clip geometry is complex enough that it will be more efficient to create it 159 // entirely in software 160 result = this->createSoftwareClipMask(genID, 161 initialState, 162 elements, 163 clipSpaceIBounds); 164 } else { 165 result = this->createAlphaClipMask(genID, 166 initialState, 167 elements, 168 clipSpaceIBounds); 169 } 170 171 if (NULL != result) { 172 // The mask's top left coord should be pinned to the rounded-out top left corner of 173 // clipSpace bounds. We determine the mask's position WRT to the render target here. 174 SkIRect rtSpaceMaskBounds = clipSpaceIBounds; 175 rtSpaceMaskBounds.offset(-clipDataIn->fOrigin); 176 setup_drawstate_aaclip(fGpu, result, rtSpaceMaskBounds); 177 fGpu->disableScissor(); 178 this->setGpuStencil(); 179 return true; 180 } 181 // if alpha clip mask creation fails fall through to the non-AA code paths 182 } 183 #endif // GR_AA_CLIP 184 185 // Either a hard (stencil buffer) clip was explicitly requested or an anti-aliased clip couldn't 186 // be created. In either case, free up the texture in the anti-aliased mask cache. 187 // TODO: this may require more investigation. Ganesh performs a lot of utility draws (e.g., 188 // clears, InOrderDrawBuffer playbacks) that hit the stencil buffer path. These may be 189 // "incorrectly" clearing the AA cache. 190 fAACache.reset(); 191 192 // If the clip is a rectangle then just set the scissor. Otherwise, create 193 // a stencil mask. 194 if (isRect) { 195 SkIRect clipRect = clipSpaceIBounds; 196 clipRect.offset(-clipDataIn->fOrigin); 197 fGpu->enableScissor(clipRect); 198 this->setGpuStencil(); 199 return true; 200 } 201 202 // use the stencil clip if we can't represent the clip as a rectangle. 203 SkIPoint clipSpaceToStencilSpaceOffset = -clipDataIn->fOrigin; 204 this->createStencilClipMask(initialState, 205 elements, 206 clipSpaceIBounds, 207 clipSpaceToStencilSpaceOffset); 208 209 // This must occur after createStencilClipMask. That function may change the scissor. Also, it 210 // only guarantees that the stencil mask is correct within the bounds it was passed, so we must 211 // use both stencil and scissor test to the bounds for the final draw. 212 SkIRect scissorSpaceIBounds(clipSpaceIBounds); 213 scissorSpaceIBounds.offset(clipSpaceToStencilSpaceOffset); 214 fGpu->enableScissor(scissorSpaceIBounds); 215 this->setGpuStencil(); 216 return true; 217 } 218 219 #define VISUALIZE_COMPLEX_CLIP 0 220 221 #if VISUALIZE_COMPLEX_CLIP 222 #include "SkRandom.h" 223 SkRandom gRandom; 224 #define SET_RANDOM_COLOR drawState->setColor(0xff000000 | gRandom.nextU()); 225 #else 226 #define SET_RANDOM_COLOR 227 #endif 228 229 namespace { 230 231 //////////////////////////////////////////////////////////////////////////////// 232 // set up the OpenGL blend function to perform the specified 233 // boolean operation for alpha clip mask creation 234 void setup_boolean_blendcoeffs(GrDrawState* drawState, SkRegion::Op op) { 235 236 switch (op) { 237 case SkRegion::kReplace_Op: 238 drawState->setBlendFunc(kOne_GrBlendCoeff, kZero_GrBlendCoeff); 239 break; 240 case SkRegion::kIntersect_Op: 241 drawState->setBlendFunc(kDC_GrBlendCoeff, kZero_GrBlendCoeff); 242 break; 243 case SkRegion::kUnion_Op: 244 drawState->setBlendFunc(kOne_GrBlendCoeff, kISC_GrBlendCoeff); 245 break; 246 case SkRegion::kXOR_Op: 247 drawState->setBlendFunc(kIDC_GrBlendCoeff, kISC_GrBlendCoeff); 248 break; 249 case SkRegion::kDifference_Op: 250 drawState->setBlendFunc(kZero_GrBlendCoeff, kISC_GrBlendCoeff); 251 break; 252 case SkRegion::kReverseDifference_Op: 253 drawState->setBlendFunc(kIDC_GrBlendCoeff, kZero_GrBlendCoeff); 254 break; 255 default: 256 GrAssert(false); 257 break; 258 } 259 } 260 261 } 262 263 //////////////////////////////////////////////////////////////////////////////// 264 bool GrClipMaskManager::drawElement(GrTexture* target, 265 const SkClipStack::Element* element, 266 GrPathRenderer* pr) { 267 GrDrawState* drawState = fGpu->drawState(); 268 269 drawState->setRenderTarget(target->asRenderTarget()); 270 271 switch (element->getType()) { 272 case Element::kRect_Type: 273 // TODO: Do rects directly to the accumulator using a aa-rect GrEffect that covers the 274 // entire mask bounds and writes 0 outside the rect. 275 if (element->isAA()) { 276 getContext()->getAARectRenderer()->fillAARect(fGpu, 277 fGpu, 278 element->getRect(), 279 false); 280 } else { 281 fGpu->drawSimpleRect(element->getRect(), NULL); 282 } 283 return true; 284 case Element::kPath_Type: { 285 SkTCopyOnFirstWrite<SkPath> path(element->getPath()); 286 if (path->isInverseFillType()) { 287 path.writable()->toggleInverseFillType(); 288 } 289 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); 290 if (NULL == pr) { 291 GrPathRendererChain::DrawType type; 292 type = element->isAA() ? GrPathRendererChain::kColorAntiAlias_DrawType : 293 GrPathRendererChain::kColor_DrawType; 294 pr = this->getContext()->getPathRenderer(*path, stroke, fGpu, false, type); 295 } 296 if (NULL == pr) { 297 return false; 298 } 299 pr->drawPath(element->getPath(), stroke, fGpu, element->isAA()); 300 break; 301 } 302 default: 303 // something is wrong if we're trying to draw an empty element. 304 GrCrash("Unexpected element type"); 305 return false; 306 } 307 return true; 308 } 309 310 bool GrClipMaskManager::canStencilAndDrawElement(GrTexture* target, 311 const SkClipStack::Element* element, 312 GrPathRenderer** pr) { 313 GrDrawState* drawState = fGpu->drawState(); 314 drawState->setRenderTarget(target->asRenderTarget()); 315 316 switch (element->getType()) { 317 case Element::kRect_Type: 318 return true; 319 case Element::kPath_Type: { 320 SkTCopyOnFirstWrite<SkPath> path(element->getPath()); 321 if (path->isInverseFillType()) { 322 path.writable()->toggleInverseFillType(); 323 } 324 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); 325 GrPathRendererChain::DrawType type = element->isAA() ? 326 GrPathRendererChain::kStencilAndColorAntiAlias_DrawType : 327 GrPathRendererChain::kStencilAndColor_DrawType; 328 *pr = this->getContext()->getPathRenderer(*path, stroke, fGpu, false, type); 329 return NULL != *pr; 330 } 331 default: 332 // something is wrong if we're trying to draw an empty element. 333 GrCrash("Unexpected element type"); 334 return false; 335 } 336 } 337 338 void GrClipMaskManager::mergeMask(GrTexture* dstMask, 339 GrTexture* srcMask, 340 SkRegion::Op op, 341 const GrIRect& dstBound, 342 const GrIRect& srcBound) { 343 GrDrawState* drawState = fGpu->drawState(); 344 SkMatrix oldMatrix = drawState->getViewMatrix(); 345 drawState->viewMatrix()->reset(); 346 347 drawState->setRenderTarget(dstMask->asRenderTarget()); 348 349 setup_boolean_blendcoeffs(drawState, op); 350 351 SkMatrix sampleM; 352 sampleM.setIDiv(srcMask->width(), srcMask->height()); 353 drawState->setEffect(0, 354 GrTextureDomainEffect::Create(srcMask, 355 sampleM, 356 GrTextureDomainEffect::MakeTexelDomain(srcMask, srcBound), 357 GrTextureDomainEffect::kDecal_WrapMode))->unref(); 358 fGpu->drawSimpleRect(SkRect::MakeFromIRect(dstBound), NULL); 359 360 drawState->disableStage(0); 361 drawState->setViewMatrix(oldMatrix); 362 } 363 364 // get a texture to act as a temporary buffer for AA clip boolean operations 365 // TODO: given the expense of createTexture we may want to just cache this too 366 void GrClipMaskManager::getTemp(int width, int height, GrAutoScratchTexture* temp) { 367 if (NULL != temp->texture()) { 368 // we've already allocated the temp texture 369 return; 370 } 371 372 GrTextureDesc desc; 373 desc.fFlags = kRenderTarget_GrTextureFlagBit|kNoStencil_GrTextureFlagBit; 374 desc.fWidth = width; 375 desc.fHeight = height; 376 desc.fConfig = kAlpha_8_GrPixelConfig; 377 378 temp->set(this->getContext(), desc); 379 } 380 381 //////////////////////////////////////////////////////////////////////////////// 382 // Handles caching & allocation (if needed) of a clip alpha-mask texture for both the sw-upload 383 // or gpu-rendered cases. Returns true if there is no more work to be done (i.e., we got a cache 384 // hit) 385 bool GrClipMaskManager::getMaskTexture(int32_t clipStackGenID, 386 const SkIRect& clipSpaceIBounds, 387 GrTexture** result) { 388 bool cached = fAACache.canReuse(clipStackGenID, clipSpaceIBounds); 389 if (!cached) { 390 391 // There isn't a suitable entry in the cache so we create a new texture to store the mask. 392 // Since we are setting up the cache we know the last lookup was a miss. Free up the 393 // currently cached mask so it can be reused. 394 fAACache.reset(); 395 396 GrTextureDesc desc; 397 desc.fFlags = kRenderTarget_GrTextureFlagBit; 398 desc.fWidth = clipSpaceIBounds.width(); 399 desc.fHeight = clipSpaceIBounds.height(); 400 desc.fConfig = kAlpha_8_GrPixelConfig; 401 402 fAACache.acquireMask(clipStackGenID, desc, clipSpaceIBounds); 403 } 404 405 *result = fAACache.getLastMask(); 406 return cached; 407 } 408 409 //////////////////////////////////////////////////////////////////////////////// 410 // Create a 8-bit clip mask in alpha 411 GrTexture* GrClipMaskManager::createAlphaClipMask(int32_t clipStackGenID, 412 InitialState initialState, 413 const ElementList& elements, 414 const SkIRect& clipSpaceIBounds) { 415 GrAssert(kNone_ClipMaskType == fCurrClipMaskType); 416 417 GrTexture* result; 418 if (this->getMaskTexture(clipStackGenID, clipSpaceIBounds, &result)) { 419 fCurrClipMaskType = kAlpha_ClipMaskType; 420 return result; 421 } 422 423 if (NULL == result) { 424 fAACache.reset(); 425 return NULL; 426 } 427 428 GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit); 429 GrDrawState* drawState = fGpu->drawState(); 430 431 GrDrawTarget::AutoGeometryPush agp(fGpu); 432 433 // The top-left of the mask corresponds to the top-left corner of the bounds. 434 SkVector clipToMaskOffset = { 435 SkIntToScalar(-clipSpaceIBounds.fLeft), 436 SkIntToScalar(-clipSpaceIBounds.fTop) 437 }; 438 // The texture may be larger than necessary, this rect represents the part of the texture 439 // we populate with a rasterization of the clip. 440 SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpaceIBounds.height()); 441 442 // We're drawing a coverage mask and want coverage to be run through the blend function. 443 drawState->enableState(GrDrawState::kCoverageDrawing_StateBit); 444 445 // Set the matrix so that rendered clip elements are transformed to mask space from clip space. 446 drawState->viewMatrix()->setTranslate(clipToMaskOffset); 447 448 // The scratch texture that we are drawing into can be substantially larger than the mask. Only 449 // clear the part that we care about. 450 fGpu->clear(&maskSpaceIBounds, 451 kAllIn_InitialState == initialState ? 0xffffffff : 0x00000000, 452 result->asRenderTarget()); 453 454 // When we use the stencil in the below loop it is important to have this clip installed. 455 // The second pass that zeros the stencil buffer renders the rect maskSpaceIBounds so the first 456 // pass must not set values outside of this bounds or stencil values outside the rect won't be 457 // cleared. 458 GrDrawTarget::AutoClipRestore acr(fGpu, maskSpaceIBounds); 459 drawState->enableState(GrDrawState::kClip_StateBit); 460 461 GrAutoScratchTexture temp; 462 // walk through each clip element and perform its set op 463 for (ElementList::Iter iter = elements.headIter(); iter.get(); iter.next()) { 464 const Element* element = iter.get(); 465 SkRegion::Op op = element->getOp(); 466 bool invert = element->isInverseFilled(); 467 468 if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op == op) { 469 GrPathRenderer* pr = NULL; 470 bool useTemp = !this->canStencilAndDrawElement(result, element, &pr); 471 GrTexture* dst; 472 // This is the bounds of the clip element in the space of the alpha-mask. The temporary 473 // mask buffer can be substantially larger than the actually clip stack element. We 474 // touch the minimum number of pixels necessary and use decal mode to combine it with 475 // the accumulator. 476 GrIRect maskSpaceElementIBounds; 477 478 if (useTemp) { 479 if (invert) { 480 maskSpaceElementIBounds = maskSpaceIBounds; 481 } else { 482 GrRect elementBounds = element->getBounds(); 483 elementBounds.offset(clipToMaskOffset); 484 elementBounds.roundOut(&maskSpaceElementIBounds); 485 } 486 487 this->getTemp(maskSpaceIBounds.fRight, maskSpaceIBounds.fBottom, &temp); 488 if (NULL == temp.texture()) { 489 fAACache.reset(); 490 return NULL; 491 } 492 dst = temp.texture(); 493 // clear the temp target and set blend to replace 494 fGpu->clear(&maskSpaceElementIBounds, 495 invert ? 0xffffffff : 0x00000000, 496 dst->asRenderTarget()); 497 setup_boolean_blendcoeffs(drawState, SkRegion::kReplace_Op); 498 499 } else { 500 // draw directly into the result with the stencil set to make the pixels affected 501 // by the clip shape be non-zero. 502 dst = result; 503 GR_STATIC_CONST_SAME_STENCIL(kStencilInElement, 504 kReplace_StencilOp, 505 kReplace_StencilOp, 506 kAlways_StencilFunc, 507 0xffff, 508 0xffff, 509 0xffff); 510 drawState->setStencil(kStencilInElement); 511 setup_boolean_blendcoeffs(drawState, op); 512 } 513 514 drawState->setAlpha(invert ? 0x00 : 0xff); 515 516 if (!this->drawElement(dst, element, pr)) { 517 fAACache.reset(); 518 return NULL; 519 } 520 521 if (useTemp) { 522 // Now draw into the accumulator using the real operation and the temp buffer as a 523 // texture 524 this->mergeMask(result, 525 temp.texture(), 526 op, 527 maskSpaceIBounds, 528 maskSpaceElementIBounds); 529 } else { 530 // Draw to the exterior pixels (those with a zero stencil value). 531 drawState->setAlpha(invert ? 0xff : 0x00); 532 GR_STATIC_CONST_SAME_STENCIL(kDrawOutsideElement, 533 kZero_StencilOp, 534 kZero_StencilOp, 535 kEqual_StencilFunc, 536 0xffff, 537 0x0000, 538 0xffff); 539 drawState->setStencil(kDrawOutsideElement); 540 fGpu->drawSimpleRect(clipSpaceIBounds); 541 drawState->disableStencil(); 542 } 543 } else { 544 // all the remaining ops can just be directly draw into the accumulation buffer 545 drawState->setAlpha(0xff); 546 setup_boolean_blendcoeffs(drawState, op); 547 this->drawElement(result, element); 548 } 549 } 550 551 fCurrClipMaskType = kAlpha_ClipMaskType; 552 return result; 553 } 554 555 //////////////////////////////////////////////////////////////////////////////// 556 // Create a 1-bit clip mask in the stencil buffer. 'devClipBounds' are in device 557 // (as opposed to canvas) coordinates 558 bool GrClipMaskManager::createStencilClipMask(InitialState initialState, 559 const ElementList& elements, 560 const SkIRect& clipSpaceIBounds, 561 const SkIPoint& clipSpaceToStencilOffset) { 562 563 GrAssert(kNone_ClipMaskType == fCurrClipMaskType); 564 565 GrDrawState* drawState = fGpu->drawState(); 566 GrAssert(drawState->isClipState()); 567 568 GrRenderTarget* rt = drawState->getRenderTarget(); 569 GrAssert(NULL != rt); 570 571 // TODO: dynamically attach a SB when needed. 572 GrStencilBuffer* stencilBuffer = rt->getStencilBuffer(); 573 if (NULL == stencilBuffer) { 574 return false; 575 } 576 int32_t genID = elements.tail()->getGenID(); 577 578 if (stencilBuffer->mustRenderClip(genID, clipSpaceIBounds, clipSpaceToStencilOffset)) { 579 580 stencilBuffer->setLastClip(genID, clipSpaceIBounds, clipSpaceToStencilOffset); 581 582 GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit); 583 drawState = fGpu->drawState(); 584 drawState->setRenderTarget(rt); 585 GrDrawTarget::AutoGeometryPush agp(fGpu); 586 587 // We set the current clip to the bounds so that our recursive draws are scissored to them. 588 SkIRect stencilSpaceIBounds(clipSpaceIBounds); 589 stencilSpaceIBounds.offset(clipSpaceToStencilOffset); 590 GrDrawTarget::AutoClipRestore acr(fGpu, stencilSpaceIBounds); 591 drawState->enableState(GrDrawState::kClip_StateBit); 592 593 // Set the matrix so that rendered clip elements are transformed from clip to stencil space. 594 SkVector translate = { 595 SkIntToScalar(clipSpaceToStencilOffset.fX), 596 SkIntToScalar(clipSpaceToStencilOffset.fY) 597 }; 598 drawState->viewMatrix()->setTranslate(translate); 599 600 #if !VISUALIZE_COMPLEX_CLIP 601 drawState->enableState(GrDrawState::kNoColorWrites_StateBit); 602 #endif 603 604 int clipBit = stencilBuffer->bits(); 605 SkASSERT((clipBit <= 16) && "Ganesh only handles 16b or smaller stencil buffers"); 606 clipBit = (1 << (clipBit-1)); 607 608 fGpu->clearStencilClip(stencilSpaceIBounds, kAllIn_InitialState == initialState); 609 610 // walk through each clip element and perform its set op 611 // with the existing clip. 612 for (ElementList::Iter iter(elements.headIter()); NULL != iter.get(); iter.next()) { 613 const Element* element = iter.get(); 614 bool fillInverted = false; 615 // enabled at bottom of loop 616 drawState->disableState(GrGpu::kModifyStencilClip_StateBit); 617 // if the target is MSAA then we want MSAA enabled when the clip is soft 618 if (rt->isMultisampled()) { 619 drawState->setState(GrDrawState::kHWAntialias_StateBit, element->isAA()); 620 } 621 622 // This will be used to determine whether the clip shape can be rendered into the 623 // stencil with arbitrary stencil settings. 624 GrPathRenderer::StencilSupport stencilSupport; 625 626 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); 627 628 SkRegion::Op op = element->getOp(); 629 630 GrPathRenderer* pr = NULL; 631 SkTCopyOnFirstWrite<SkPath> clipPath; 632 if (Element::kRect_Type == element->getType()) { 633 stencilSupport = GrPathRenderer::kNoRestriction_StencilSupport; 634 fillInverted = false; 635 } else { 636 GrAssert(Element::kPath_Type == element->getType()); 637 clipPath.init(element->getPath()); 638 fillInverted = clipPath->isInverseFillType(); 639 if (fillInverted) { 640 clipPath.writable()->toggleInverseFillType(); 641 } 642 pr = this->getContext()->getPathRenderer(*clipPath, 643 stroke, 644 fGpu, 645 false, 646 GrPathRendererChain::kStencilOnly_DrawType, 647 &stencilSupport); 648 if (NULL == pr) { 649 return false; 650 } 651 } 652 653 int passes; 654 GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses]; 655 656 bool canRenderDirectToStencil = 657 GrPathRenderer::kNoRestriction_StencilSupport == stencilSupport; 658 bool canDrawDirectToClip; // Given the renderer, the element, 659 // fill rule, and set operation can 660 // we render the element directly to 661 // stencil bit used for clipping. 662 canDrawDirectToClip = GrStencilSettings::GetClipPasses(op, 663 canRenderDirectToStencil, 664 clipBit, 665 fillInverted, 666 &passes, 667 stencilSettings); 668 669 // draw the element to the client stencil bits if necessary 670 if (!canDrawDirectToClip) { 671 GR_STATIC_CONST_SAME_STENCIL(gDrawToStencil, 672 kIncClamp_StencilOp, 673 kIncClamp_StencilOp, 674 kAlways_StencilFunc, 675 0xffff, 676 0x0000, 677 0xffff); 678 SET_RANDOM_COLOR 679 if (Element::kRect_Type == element->getType()) { 680 *drawState->stencil() = gDrawToStencil; 681 fGpu->drawSimpleRect(element->getRect(), NULL); 682 } else { 683 GrAssert(Element::kPath_Type == element->getType()); 684 if (canRenderDirectToStencil) { 685 *drawState->stencil() = gDrawToStencil; 686 pr->drawPath(*clipPath, stroke, fGpu, false); 687 } else { 688 pr->stencilPath(*clipPath, stroke, fGpu); 689 } 690 } 691 } 692 693 // now we modify the clip bit by rendering either the clip 694 // element directly or a bounding rect of the entire clip. 695 drawState->enableState(GrGpu::kModifyStencilClip_StateBit); 696 for (int p = 0; p < passes; ++p) { 697 *drawState->stencil() = stencilSettings[p]; 698 if (canDrawDirectToClip) { 699 if (Element::kRect_Type == element->getType()) { 700 SET_RANDOM_COLOR 701 fGpu->drawSimpleRect(element->getRect(), NULL); 702 } else { 703 GrAssert(Element::kPath_Type == element->getType()); 704 SET_RANDOM_COLOR 705 pr->drawPath(*clipPath, stroke, fGpu, false); 706 } 707 } else { 708 SET_RANDOM_COLOR 709 // The view matrix is setup to do clip space -> stencil space translation, so 710 // draw rect in clip space. 711 fGpu->drawSimpleRect(SkRect::MakeFromIRect(clipSpaceIBounds), NULL); 712 } 713 } 714 } 715 } 716 // set this last because recursive draws may overwrite it back to kNone. 717 GrAssert(kNone_ClipMaskType == fCurrClipMaskType); 718 fCurrClipMaskType = kStencil_ClipMaskType; 719 return true; 720 } 721 722 723 // mapping of clip-respecting stencil funcs to normal stencil funcs 724 // mapping depends on whether stencil-clipping is in effect. 725 static const GrStencilFunc 726 gSpecialToBasicStencilFunc[2][kClipStencilFuncCount] = { 727 {// Stencil-Clipping is DISABLED, we are effectively always inside the clip 728 // In the Clip Funcs 729 kAlways_StencilFunc, // kAlwaysIfInClip_StencilFunc 730 kEqual_StencilFunc, // kEqualIfInClip_StencilFunc 731 kLess_StencilFunc, // kLessIfInClip_StencilFunc 732 kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc 733 // Special in the clip func that forces user's ref to be 0. 734 kNotEqual_StencilFunc, // kNonZeroIfInClip_StencilFunc 735 // make ref 0 and do normal nequal. 736 }, 737 {// Stencil-Clipping is ENABLED 738 // In the Clip Funcs 739 kEqual_StencilFunc, // kAlwaysIfInClip_StencilFunc 740 // eq stencil clip bit, mask 741 // out user bits. 742 743 kEqual_StencilFunc, // kEqualIfInClip_StencilFunc 744 // add stencil bit to mask and ref 745 746 kLess_StencilFunc, // kLessIfInClip_StencilFunc 747 kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc 748 // for both of these we can add 749 // the clip bit to the mask and 750 // ref and compare as normal 751 // Special in the clip func that forces user's ref to be 0. 752 kLess_StencilFunc, // kNonZeroIfInClip_StencilFunc 753 // make ref have only the clip bit set 754 // and make comparison be less 755 // 10..0 < 1..user_bits.. 756 } 757 }; 758 759 namespace { 760 // Sets the settings to clip against the stencil buffer clip while ignoring the 761 // client bits. 762 const GrStencilSettings& basic_apply_stencil_clip_settings() { 763 // stencil settings to use when clip is in stencil 764 GR_STATIC_CONST_SAME_STENCIL_STRUCT(gSettings, 765 kKeep_StencilOp, 766 kKeep_StencilOp, 767 kAlwaysIfInClip_StencilFunc, 768 0x0000, 769 0x0000, 770 0x0000); 771 return *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&gSettings); 772 } 773 } 774 775 void GrClipMaskManager::setGpuStencil() { 776 // We make two copies of the StencilSettings here (except in the early 777 // exit scenario. One copy from draw state to the stack var. Then another 778 // from the stack var to the gpu. We could make this class hold a ptr to 779 // GrGpu's fStencilSettings and eliminate the stack copy here. 780 781 const GrDrawState& drawState = fGpu->getDrawState(); 782 783 // use stencil for clipping if clipping is enabled and the clip 784 // has been written into the stencil. 785 GrClipMaskManager::StencilClipMode clipMode; 786 if (this->isClipInStencil() && drawState.isClipState()) { 787 clipMode = GrClipMaskManager::kRespectClip_StencilClipMode; 788 // We can't be modifying the clip and respecting it at the same time. 789 GrAssert(!drawState.isStateFlagEnabled( 790 GrGpu::kModifyStencilClip_StateBit)); 791 } else if (drawState.isStateFlagEnabled( 792 GrGpu::kModifyStencilClip_StateBit)) { 793 clipMode = GrClipMaskManager::kModifyClip_StencilClipMode; 794 } else { 795 clipMode = GrClipMaskManager::kIgnoreClip_StencilClipMode; 796 } 797 798 GrStencilSettings settings; 799 // The GrGpu client may not be using the stencil buffer but we may need to 800 // enable it in order to respect a stencil clip. 801 if (drawState.getStencil().isDisabled()) { 802 if (GrClipMaskManager::kRespectClip_StencilClipMode == clipMode) { 803 settings = basic_apply_stencil_clip_settings(); 804 } else { 805 fGpu->disableStencil(); 806 return; 807 } 808 } else { 809 settings = drawState.getStencil(); 810 } 811 812 // TODO: dynamically attach a stencil buffer 813 int stencilBits = 0; 814 GrStencilBuffer* stencilBuffer = 815 drawState.getRenderTarget()->getStencilBuffer(); 816 if (NULL != stencilBuffer) { 817 stencilBits = stencilBuffer->bits(); 818 } 819 820 GrAssert(fGpu->getCaps().stencilWrapOpsSupport() || !settings.usesWrapOp()); 821 GrAssert(fGpu->getCaps().twoSidedStencilSupport() || !settings.isTwoSided()); 822 this->adjustStencilParams(&settings, clipMode, stencilBits); 823 fGpu->setStencilSettings(settings); 824 } 825 826 void GrClipMaskManager::adjustStencilParams(GrStencilSettings* settings, 827 StencilClipMode mode, 828 int stencilBitCnt) { 829 GrAssert(stencilBitCnt > 0); 830 831 if (kModifyClip_StencilClipMode == mode) { 832 // We assume that this clip manager itself is drawing to the GrGpu and 833 // has already setup the correct values. 834 return; 835 } 836 837 unsigned int clipBit = (1 << (stencilBitCnt - 1)); 838 unsigned int userBits = clipBit - 1; 839 840 GrStencilSettings::Face face = GrStencilSettings::kFront_Face; 841 bool twoSided = fGpu->getCaps().twoSidedStencilSupport(); 842 843 bool finished = false; 844 while (!finished) { 845 GrStencilFunc func = settings->func(face); 846 uint16_t writeMask = settings->writeMask(face); 847 uint16_t funcMask = settings->funcMask(face); 848 uint16_t funcRef = settings->funcRef(face); 849 850 GrAssert((unsigned) func < kStencilFuncCount); 851 852 writeMask &= userBits; 853 854 if (func >= kBasicStencilFuncCount) { 855 int respectClip = kRespectClip_StencilClipMode == mode; 856 if (respectClip) { 857 // The GrGpu class should have checked this 858 GrAssert(this->isClipInStencil()); 859 switch (func) { 860 case kAlwaysIfInClip_StencilFunc: 861 funcMask = clipBit; 862 funcRef = clipBit; 863 break; 864 case kEqualIfInClip_StencilFunc: 865 case kLessIfInClip_StencilFunc: 866 case kLEqualIfInClip_StencilFunc: 867 funcMask = (funcMask & userBits) | clipBit; 868 funcRef = (funcRef & userBits) | clipBit; 869 break; 870 case kNonZeroIfInClip_StencilFunc: 871 funcMask = (funcMask & userBits) | clipBit; 872 funcRef = clipBit; 873 break; 874 default: 875 GrCrash("Unknown stencil func"); 876 } 877 } else { 878 funcMask &= userBits; 879 funcRef &= userBits; 880 } 881 const GrStencilFunc* table = 882 gSpecialToBasicStencilFunc[respectClip]; 883 func = table[func - kBasicStencilFuncCount]; 884 GrAssert(func >= 0 && func < kBasicStencilFuncCount); 885 } else { 886 funcMask &= userBits; 887 funcRef &= userBits; 888 } 889 890 settings->setFunc(face, func); 891 settings->setWriteMask(face, writeMask); 892 settings->setFuncMask(face, funcMask); 893 settings->setFuncRef(face, funcRef); 894 895 if (GrStencilSettings::kFront_Face == face) { 896 face = GrStencilSettings::kBack_Face; 897 finished = !twoSided; 898 } else { 899 finished = true; 900 } 901 } 902 if (!twoSided) { 903 settings->copyFrontSettingsToBack(); 904 } 905 } 906 907 //////////////////////////////////////////////////////////////////////////////// 908 GrTexture* GrClipMaskManager::createSoftwareClipMask(int32_t clipStackGenID, 909 GrReducedClip::InitialState initialState, 910 const GrReducedClip::ElementList& elements, 911 const SkIRect& clipSpaceIBounds) { 912 GrAssert(kNone_ClipMaskType == fCurrClipMaskType); 913 914 GrTexture* result; 915 if (this->getMaskTexture(clipStackGenID, clipSpaceIBounds, &result)) { 916 return result; 917 } 918 919 if (NULL == result) { 920 fAACache.reset(); 921 return NULL; 922 } 923 924 // The mask texture may be larger than necessary. We round out the clip space bounds and pin 925 // the top left corner of the resulting rect to the top left of the texture. 926 SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpaceIBounds.height()); 927 928 GrSWMaskHelper helper(this->getContext()); 929 930 SkMatrix matrix; 931 matrix.setTranslate(SkIntToScalar(-clipSpaceIBounds.fLeft), 932 SkIntToScalar(-clipSpaceIBounds.fTop)); 933 helper.init(maskSpaceIBounds, &matrix); 934 935 helper.clear(kAllIn_InitialState == initialState ? 0xFF : 0x00); 936 937 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); 938 939 for (ElementList::Iter iter(elements.headIter()) ; NULL != iter.get(); iter.next()) { 940 941 const Element* element = iter.get(); 942 SkRegion::Op op = element->getOp(); 943 944 if (SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op == op) { 945 // Intersect and reverse difference require modifying pixels outside of the geometry 946 // that is being "drawn". In both cases we erase all the pixels outside of the geometry 947 // but leave the pixels inside the geometry alone. For reverse difference we invert all 948 // the pixels before clearing the ones outside the geometry. 949 if (SkRegion::kReverseDifference_Op == op) { 950 SkRect temp = SkRect::MakeFromIRect(clipSpaceIBounds); 951 // invert the entire scene 952 helper.draw(temp, SkRegion::kXOR_Op, false, 0xFF); 953 } 954 955 if (Element::kRect_Type == element->getType()) { 956 // convert the rect to a path so we can invert the fill 957 SkPath temp; 958 temp.addRect(element->getRect()); 959 temp.setFillType(SkPath::kInverseEvenOdd_FillType); 960 961 helper.draw(temp, stroke, SkRegion::kReplace_Op, 962 element->isAA(), 963 0x00); 964 } else { 965 GrAssert(Element::kPath_Type == element->getType()); 966 SkPath clipPath = element->getPath(); 967 clipPath.toggleInverseFillType(); 968 helper.draw(clipPath, stroke, 969 SkRegion::kReplace_Op, 970 element->isAA(), 971 0x00); 972 } 973 974 continue; 975 } 976 977 // The other ops (union, xor, diff) only affect pixels inside 978 // the geometry so they can just be drawn normally 979 if (Element::kRect_Type == element->getType()) { 980 helper.draw(element->getRect(), op, element->isAA(), 0xFF); 981 } else { 982 GrAssert(Element::kPath_Type == element->getType()); 983 helper.draw(element->getPath(), stroke, op, element->isAA(), 0xFF); 984 } 985 } 986 987 helper.toTexture(result, kAllIn_InitialState == initialState ? 0xFF : 0x00); 988 989 fCurrClipMaskType = kAlpha_ClipMaskType; 990 return result; 991 } 992 993 //////////////////////////////////////////////////////////////////////////////// 994 void GrClipMaskManager::releaseResources() { 995 fAACache.releaseResources(); 996 } 997