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