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