OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2016 Google Inc. | 2 * Copyright 2016 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "GrReducedClip.h" | 8 #include "GrReducedClip.h" |
9 | 9 |
| 10 #include "GrAppliedClip.h" |
10 #include "GrClip.h" | 11 #include "GrClip.h" |
| 12 #include "GrColor.h" |
| 13 #include "GrContextPriv.h" |
| 14 #include "GrDrawContext.h" |
| 15 #include "GrDrawContextPriv.h" |
| 16 #include "GrDrawingManager.h" |
| 17 #include "GrFixedClip.h" |
| 18 #include "GrPathRenderer.h" |
| 19 #include "GrStyle.h" |
| 20 #include "GrUserStencilSettings.h" |
11 | 21 |
12 typedef SkClipStack::Element Element; | 22 typedef SkClipStack::Element Element; |
13 | 23 |
14 /** | 24 /** |
15 * There are plenty of optimizations that could be added here. Maybe flips could
be folded into | 25 * There are plenty of optimizations that could be added here. Maybe flips could
be folded into |
16 * earlier operations. Or would inserting flips and reversing earlier ops ever b
e a win? Perhaps | 26 * earlier operations. Or would inserting flips and reversing earlier ops ever b
e a win? Perhaps |
17 * for the case where the bounds are kInsideOut_BoundsType. We could restrict ea
rlier operations | 27 * for the case where the bounds are kInsideOut_BoundsType. We could restrict ea
rlier operations |
18 * based on later intersect operations, and perhaps remove intersect-rects. We c
ould optionally | 28 * based on later intersect operations, and perhaps remove intersect-rects. We c
ould optionally |
19 * take a rect in case the caller knows a bound on what is to be drawn through t
his clip. | 29 * take a rect in case the caller knows a bound on what is to be drawn through t
his clip. |
20 */ | 30 */ |
(...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
414 SkASSERT(fHasIBounds); | 424 SkASSERT(fHasIBounds); |
415 if (!fIBounds.intersect(irect)) { | 425 if (!fIBounds.intersect(irect)) { |
416 fHasIBounds = false; | 426 fHasIBounds = false; |
417 fElements.reset(); | 427 fElements.reset(); |
418 fRequiresAA = false; | 428 fRequiresAA = false; |
419 fInitialState = InitialState::kAllOut; | 429 fInitialState = InitialState::kAllOut; |
420 return false; | 430 return false; |
421 } | 431 } |
422 return true; | 432 return true; |
423 } | 433 } |
| 434 |
| 435 //////////////////////////////////////////////////////////////////////////////// |
| 436 // Create a 8-bit clip mask in alpha |
| 437 |
| 438 static bool stencil_element(GrDrawContext* dc, |
| 439 const GrFixedClip& clip, |
| 440 const GrUserStencilSettings* ss, |
| 441 const SkMatrix& viewMatrix, |
| 442 const SkClipStack::Element* element) { |
| 443 |
| 444 // TODO: Draw rrects directly here. |
| 445 switch (element->getType()) { |
| 446 case Element::kEmpty_Type: |
| 447 SkDEBUGFAIL("Should never get here with an empty element."); |
| 448 break; |
| 449 case Element::kRect_Type: |
| 450 return dc->drawContextPriv().drawAndStencilRect(clip, ss, |
| 451 element->getOp(), |
| 452 element->isInverseFi
lled(), |
| 453 element->isAA(), |
| 454 viewMatrix, element-
>getRect()); |
| 455 break; |
| 456 default: { |
| 457 SkPath path; |
| 458 element->asPath(&path); |
| 459 if (path.isInverseFillType()) { |
| 460 path.toggleInverseFillType(); |
| 461 } |
| 462 |
| 463 return dc->drawContextPriv().drawAndStencilPath(clip, ss, |
| 464 element->getOp(), |
| 465 element->isInverseFi
lled(), |
| 466 element->isAA(), vie
wMatrix, path); |
| 467 break; |
| 468 } |
| 469 } |
| 470 |
| 471 return false; |
| 472 } |
| 473 |
| 474 static void draw_element(GrDrawContext* dc, |
| 475 const GrClip& clip, // TODO: can this just always be Wi
deOpen? |
| 476 const GrPaint &paint, |
| 477 const SkMatrix& viewMatrix, |
| 478 const SkClipStack::Element* element) { |
| 479 |
| 480 // TODO: Draw rrects directly here. |
| 481 switch (element->getType()) { |
| 482 case Element::kEmpty_Type: |
| 483 SkDEBUGFAIL("Should never get here with an empty element."); |
| 484 break; |
| 485 case Element::kRect_Type: |
| 486 dc->drawRect(clip, paint, viewMatrix, element->getRect()); |
| 487 break; |
| 488 default: { |
| 489 SkPath path; |
| 490 element->asPath(&path); |
| 491 if (path.isInverseFillType()) { |
| 492 path.toggleInverseFillType(); |
| 493 } |
| 494 |
| 495 dc->drawPath(clip, paint, viewMatrix, path, GrStyle::SimpleFill()); |
| 496 break; |
| 497 } |
| 498 } |
| 499 } |
| 500 |
| 501 bool GrReducedClip::drawAlphaClipMask(GrDrawContext* dc) const { |
| 502 // The texture may be larger than necessary, this rect represents the part o
f the texture |
| 503 // we populate with a rasterization of the clip. |
| 504 GrFixedClip clip(SkIRect::MakeWH(fIBounds.width(), fIBounds.height())); |
| 505 |
| 506 // The scratch texture that we are drawing into can be substantially larger
than the mask. Only |
| 507 // clear the part that we care about. |
| 508 GrColor initialCoverage = InitialState::kAllIn == this->initialState() ? -1
: 0; |
| 509 dc->drawContextPriv().clear(clip, initialCoverage, true); |
| 510 |
| 511 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip space. |
| 512 SkMatrix translate; |
| 513 translate.setTranslate(SkIntToScalar(-fIBounds.left()), SkIntToScalar(-fIBou
nds.top())); |
| 514 |
| 515 // walk through each clip element and perform its set op |
| 516 for (ElementList::Iter iter(fElements); iter.get(); iter.next()) { |
| 517 const Element* element = iter.get(); |
| 518 SkRegion::Op op = element->getOp(); |
| 519 bool invert = element->isInverseFilled(); |
| 520 if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDiffere
nce_Op == op) { |
| 521 // draw directly into the result with the stencil set to make the pi
xels affected |
| 522 // by the clip shape be non-zero. |
| 523 static constexpr GrUserStencilSettings kStencilInElement( |
| 524 GrUserStencilSettings::StaticInit< |
| 525 0xffff, |
| 526 GrUserStencilTest::kAlways, |
| 527 0xffff, |
| 528 GrUserStencilOp::kReplace, |
| 529 GrUserStencilOp::kReplace, |
| 530 0xffff>() |
| 531 ); |
| 532 if (!stencil_element(dc, clip, &kStencilInElement, translate, elemen
t)) { |
| 533 return false; |
| 534 } |
| 535 |
| 536 // Draw to the exterior pixels (those with a zero stencil value). |
| 537 static constexpr GrUserStencilSettings kDrawOutsideElement( |
| 538 GrUserStencilSettings::StaticInit< |
| 539 0x0000, |
| 540 GrUserStencilTest::kEqual, |
| 541 0xffff, |
| 542 GrUserStencilOp::kZero, |
| 543 GrUserStencilOp::kZero, |
| 544 0xffff>() |
| 545 ); |
| 546 if (!dc->drawContextPriv().drawAndStencilRect(clip, &kDrawOutsideEle
ment, |
| 547 op, !invert, false, |
| 548 translate, |
| 549 SkRect::Make(fIBounds)
)) { |
| 550 return false; |
| 551 } |
| 552 } else { |
| 553 // all the remaining ops can just be directly draw into the accumula
tion buffer |
| 554 GrPaint paint; |
| 555 paint.setAntiAlias(element->isAA()); |
| 556 paint.setCoverageSetOpXPFactory(op, false); |
| 557 |
| 558 draw_element(dc, clip, paint, translate, element); |
| 559 } |
| 560 } |
| 561 |
| 562 return true; |
| 563 } |
| 564 |
| 565 //////////////////////////////////////////////////////////////////////////////// |
| 566 // Create a 1-bit clip mask in the stencil buffer. |
| 567 |
| 568 class StencilClip final : public GrClip { |
| 569 public: |
| 570 StencilClip(const SkIRect& scissorRect) : fFixedClip(scissorRect) {} |
| 571 const GrFixedClip& fixedClip() const { return fFixedClip; } |
| 572 |
| 573 private: |
| 574 bool quickContains(const SkRect&) const final { |
| 575 return false; |
| 576 } |
| 577 void getConservativeBounds(int width, int height, SkIRect* devResult, bool*
iior) const final { |
| 578 fFixedClip.getConservativeBounds(width, height, devResult, iior); |
| 579 } |
| 580 bool isRRect(const SkRect& rtBounds, SkRRect* rr, bool* aa) const final { |
| 581 return false; |
| 582 } |
| 583 bool apply(GrContext* context, GrDrawContext* drawContext, bool useHWAA, |
| 584 bool hasUserStencilSettings, GrAppliedClip* out) const final { |
| 585 if (!fFixedClip.apply(context, drawContext, useHWAA, hasUserStencilSetti
ngs, out)) { |
| 586 return false; |
| 587 } |
| 588 out->addStencilClip(); |
| 589 return true; |
| 590 } |
| 591 |
| 592 GrFixedClip fFixedClip; |
| 593 |
| 594 typedef GrClip INHERITED; |
| 595 }; |
| 596 |
| 597 bool GrReducedClip::drawStencilClipMask(GrContext* context, |
| 598 GrDrawContext* drawContext, |
| 599 const SkIPoint& clipOrigin) const { |
| 600 // We set the current clip to the bounds so that our recursive draws are sci
ssored to them. |
| 601 StencilClip stencilClip(fIBounds.makeOffset(-clipOrigin.x(), -clipOrigin.y()
)); |
| 602 |
| 603 bool initialState = InitialState::kAllIn == this->initialState(); |
| 604 drawContext->drawContextPriv().clearStencilClip(stencilClip.fixedClip(), ini
tialState); |
| 605 |
| 606 // Set the matrix so that rendered clip elements are transformed from clip t
o stencil space. |
| 607 SkMatrix viewMatrix; |
| 608 viewMatrix.setTranslate(SkIntToScalar(-clipOrigin.x()), SkIntToScalar(-clipO
rigin.y())); |
| 609 |
| 610 // walk through each clip element and perform its set op |
| 611 // with the existing clip. |
| 612 for (ElementList::Iter iter(fElements); iter.get(); iter.next()) { |
| 613 const Element* element = iter.get(); |
| 614 bool useHWAA = element->isAA() && drawContext->isStencilBufferMultisampl
ed(); |
| 615 |
| 616 bool fillInverted = false; |
| 617 |
| 618 // This will be used to determine whether the clip shape can be rendered
into the |
| 619 // stencil with arbitrary stencil settings. |
| 620 GrPathRenderer::StencilSupport stencilSupport; |
| 621 |
| 622 SkRegion::Op op = element->getOp(); |
| 623 |
| 624 GrPathRenderer* pr = nullptr; |
| 625 SkPath clipPath; |
| 626 if (Element::kRect_Type == element->getType()) { |
| 627 stencilSupport = GrPathRenderer::kNoRestriction_StencilSupport; |
| 628 fillInverted = false; |
| 629 } else { |
| 630 element->asPath(&clipPath); |
| 631 fillInverted = clipPath.isInverseFillType(); |
| 632 if (fillInverted) { |
| 633 clipPath.toggleInverseFillType(); |
| 634 } |
| 635 |
| 636 GrShape shape(clipPath, GrStyle::SimpleFill()); |
| 637 GrPathRenderer::CanDrawPathArgs canDrawArgs; |
| 638 canDrawArgs.fShaderCaps = context->caps()->shaderCaps(); |
| 639 canDrawArgs.fViewMatrix = &viewMatrix; |
| 640 canDrawArgs.fShape = &shape; |
| 641 canDrawArgs.fAntiAlias = false; |
| 642 canDrawArgs.fHasUserStencilSettings = false; |
| 643 canDrawArgs.fIsStencilBufferMSAA = drawContext->isStencilBufferMulti
sampled(); |
| 644 |
| 645 GrDrawingManager* dm = context->contextPriv().drawingManager(); |
| 646 pr = dm->getPathRenderer(canDrawArgs, false, |
| 647 GrPathRendererChain::kStencilOnly_DrawType, |
| 648 &stencilSupport); |
| 649 if (!pr) { |
| 650 return false; |
| 651 } |
| 652 } |
| 653 |
| 654 bool canRenderDirectToStencil = |
| 655 GrPathRenderer::kNoRestriction_StencilSupport == stencilSupport; |
| 656 bool drawDirectToClip; // Given the renderer, the element, |
| 657 // fill rule, and set operation should |
| 658 // we render the element directly to |
| 659 // stencil bit used for clipping. |
| 660 GrUserStencilSettings const* const* stencilPasses = |
| 661 GrStencilSettings::GetClipPasses(op, canRenderDirectToStencil, fillI
nverted, |
| 662 &drawDirectToClip); |
| 663 |
| 664 // draw the element to the client stencil bits if necessary |
| 665 if (!drawDirectToClip) { |
| 666 static constexpr GrUserStencilSettings kDrawToStencil( |
| 667 GrUserStencilSettings::StaticInit< |
| 668 0x0000, |
| 669 GrUserStencilTest::kAlways, |
| 670 0xffff, |
| 671 GrUserStencilOp::kIncMaybeClamp, |
| 672 GrUserStencilOp::kIncMaybeClamp, |
| 673 0xffff>() |
| 674 ); |
| 675 if (Element::kRect_Type == element->getType()) { |
| 676 drawContext->drawContextPriv().stencilRect(stencilClip.fixedClip
(), |
| 677 &kDrawToStencil, useH
WAA, |
| 678 viewMatrix, element->
getRect()); |
| 679 } else { |
| 680 if (!clipPath.isEmpty()) { |
| 681 GrShape shape(clipPath, GrStyle::SimpleFill()); |
| 682 if (canRenderDirectToStencil) { |
| 683 GrPaint paint; |
| 684 paint.setXPFactory(GrDisableColorXPFactory::Make()); |
| 685 paint.setAntiAlias(element->isAA()); |
| 686 |
| 687 GrPathRenderer::DrawPathArgs args; |
| 688 args.fResourceProvider = context->resourceProvider(); |
| 689 args.fPaint = &paint; |
| 690 args.fUserStencilSettings = &kDrawToStencil; |
| 691 args.fDrawContext = drawContext; |
| 692 args.fClip = &stencilClip.fixedClip(); |
| 693 args.fViewMatrix = &viewMatrix; |
| 694 args.fShape = &shape; |
| 695 args.fAntiAlias = false; |
| 696 args.fGammaCorrect = false; |
| 697 pr->drawPath(args); |
| 698 } else { |
| 699 GrPathRenderer::StencilPathArgs args; |
| 700 args.fResourceProvider = context->resourceProvider(); |
| 701 args.fDrawContext = drawContext; |
| 702 args.fClip = &stencilClip.fixedClip(); |
| 703 args.fViewMatrix = &viewMatrix; |
| 704 args.fIsAA = element->isAA(); |
| 705 args.fShape = &shape; |
| 706 pr->stencilPath(args); |
| 707 } |
| 708 } |
| 709 } |
| 710 } |
| 711 |
| 712 // now we modify the clip bit by rendering either the clip |
| 713 // element directly or a bounding rect of the entire clip. |
| 714 for (GrUserStencilSettings const* const* pass = stencilPasses; *pass; ++
pass) { |
| 715 if (drawDirectToClip) { |
| 716 if (Element::kRect_Type == element->getType()) { |
| 717 drawContext->drawContextPriv().stencilRect(stencilClip, *pas
s, useHWAA, |
| 718 viewMatrix, eleme
nt->getRect()); |
| 719 } else { |
| 720 GrShape shape(clipPath, GrStyle::SimpleFill()); |
| 721 GrPaint paint; |
| 722 paint.setXPFactory(GrDisableColorXPFactory::Make()); |
| 723 paint.setAntiAlias(element->isAA()); |
| 724 GrPathRenderer::DrawPathArgs args; |
| 725 args.fResourceProvider = context->resourceProvider(); |
| 726 args.fPaint = &paint; |
| 727 args.fUserStencilSettings = *pass; |
| 728 args.fDrawContext = drawContext; |
| 729 args.fClip = &stencilClip; |
| 730 args.fViewMatrix = &viewMatrix; |
| 731 args.fShape = &shape; |
| 732 args.fAntiAlias = false; |
| 733 args.fGammaCorrect = false; |
| 734 pr->drawPath(args); |
| 735 } |
| 736 } else { |
| 737 // The view matrix is setup to do clip space -> stencil space tr
anslation, so |
| 738 // draw rect in clip space. |
| 739 drawContext->drawContextPriv().stencilRect(stencilClip, *pass, |
| 740 false, viewMatrix, |
| 741 SkRect::Make(fIBounds
)); |
| 742 } |
| 743 } |
| 744 } |
| 745 return true; |
| 746 } |
OLD | NEW |