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