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