| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 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 "GrClipMaskManager.h" | 8 #include "GrClipMaskManager.h" |
| 9 #include "GrCaps.h" | 9 #include "GrCaps.h" |
| 10 #include "GrDrawingManager.h" | 10 #include "GrDrawingManager.h" |
| (...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 363 !SkRect::Make(scissorSpaceIBounds).contains(*devBounds)) { | 363 !SkRect::Make(scissorSpaceIBounds).contains(*devBounds)) { |
| 364 out->fScissorState.set(scissorSpaceIBounds); | 364 out->fScissorState.set(scissorSpaceIBounds); |
| 365 } | 365 } |
| 366 out->fClipCoverageFP.reset(clipFP); | 366 out->fClipCoverageFP.reset(clipFP); |
| 367 return true; | 367 return true; |
| 368 } | 368 } |
| 369 } | 369 } |
| 370 | 370 |
| 371 // If the stencil buffer is multisampled we can use it to do everything. | 371 // If the stencil buffer is multisampled we can use it to do everything. |
| 372 if (!rt->isStencilBufferMultisampled() && requiresAA) { | 372 if (!rt->isStencilBufferMultisampled() && requiresAA) { |
| 373 SkAutoTUnref<GrTexture> result; | 373 sk_sp<GrTexture> result; |
| 374 | 374 |
| 375 // The top-left of the mask corresponds to the top-left corner of the bo
unds. | 375 // The top-left of the mask corresponds to the top-left corner of the bo
unds. |
| 376 SkVector clipToMaskOffset = { | 376 SkVector clipToMaskOffset = { |
| 377 SkIntToScalar(-clipSpaceIBounds.fLeft), | 377 SkIntToScalar(-clipSpaceIBounds.fLeft), |
| 378 SkIntToScalar(-clipSpaceIBounds.fTop) | 378 SkIntToScalar(-clipSpaceIBounds.fTop) |
| 379 }; | 379 }; |
| 380 | 380 |
| 381 if (UseSWOnlyPath(this->getContext(), pipelineBuilder, rt, clipToMaskOff
set, elements)) { | 381 if (UseSWOnlyPath(this->getContext(), pipelineBuilder, rt, clipToMaskOff
set, elements)) { |
| 382 // The clip geometry is complex enough that it will be more efficien
t to create it | 382 // The clip geometry is complex enough that it will be more efficien
t to create it |
| 383 // entirely in software | 383 // entirely in software |
| 384 result.reset(CreateSoftwareClipMask(this->getContext(), | 384 result = CreateSoftwareClipMask(this->getContext(), |
| 385 genID, | 385 genID, |
| 386 initialState, | 386 initialState, |
| 387 elements, | 387 elements, |
| 388 clipToMaskOffset, | 388 clipToMaskOffset, |
| 389 clipSpaceIBounds)); | 389 clipSpaceIBounds); |
| 390 } else { | 390 } else { |
| 391 result.reset(CreateAlphaClipMask(this->getContext(), | 391 result = CreateAlphaClipMask(this->getContext(), |
| 392 genID, | 392 genID, |
| 393 initialState, | 393 initialState, |
| 394 elements, | 394 elements, |
| 395 clipToMaskOffset, | 395 clipToMaskOffset, |
| 396 clipSpaceIBounds)); | 396 clipSpaceIBounds); |
| 397 // If createAlphaClipMask fails it means UseSWOnlyPath has a bug | 397 // If createAlphaClipMask fails it means UseSWOnlyPath has a bug |
| 398 SkASSERT(result); | 398 SkASSERT(result); |
| 399 } | 399 } |
| 400 | 400 |
| 401 if (result) { | 401 if (result) { |
| 402 // The mask's top left coord should be pinned to the rounded-out top
left corner of | 402 // The mask's top left coord should be pinned to the rounded-out top
left corner of |
| 403 // clipSpace bounds. We determine the mask's position WRT to the ren
der target here. | 403 // clipSpace bounds. We determine the mask's position WRT to the ren
der target here. |
| 404 SkIRect rtSpaceMaskBounds = clipSpaceIBounds; | 404 SkIRect rtSpaceMaskBounds = clipSpaceIBounds; |
| 405 rtSpaceMaskBounds.offset(-clip.origin()); | 405 rtSpaceMaskBounds.offset(-clip.origin()); |
| 406 out->fClipCoverageFP.reset(create_fp_for_mask(result, rtSpaceMaskBou
nds)); | 406 out->fClipCoverageFP.reset(create_fp_for_mask(result.get(), rtSpaceM
askBounds)); |
| 407 return true; | 407 return true; |
| 408 } | 408 } |
| 409 // if alpha clip mask creation fails fall through to the non-AA code pat
hs | 409 // if alpha clip mask creation fails fall through to the non-AA code pat
hs |
| 410 } | 410 } |
| 411 | 411 |
| 412 // use the stencil clip if we can't represent the clip as a rectangle. | 412 // use the stencil clip if we can't represent the clip as a rectangle. |
| 413 SkIPoint clipSpaceToStencilSpaceOffset = -clip.origin(); | 413 SkIPoint clipSpaceToStencilSpaceOffset = -clip.origin(); |
| 414 this->createStencilClipMask(rt, | 414 this->createStencilClipMask(rt, |
| 415 genID, | 415 genID, |
| 416 initialState, | 416 initialState, |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 495 // Create a 8-bit clip mask in alpha | 495 // Create a 8-bit clip mask in alpha |
| 496 | 496 |
| 497 static void GetClipMaskKey(int32_t clipGenID, const SkIRect& bounds, GrUniqueKey
* key) { | 497 static void GetClipMaskKey(int32_t clipGenID, const SkIRect& bounds, GrUniqueKey
* key) { |
| 498 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); | 498 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); |
| 499 GrUniqueKey::Builder builder(key, kDomain, 3); | 499 GrUniqueKey::Builder builder(key, kDomain, 3); |
| 500 builder[0] = clipGenID; | 500 builder[0] = clipGenID; |
| 501 builder[1] = SkToU16(bounds.fLeft) | (SkToU16(bounds.fRight) << 16); | 501 builder[1] = SkToU16(bounds.fLeft) | (SkToU16(bounds.fRight) << 16); |
| 502 builder[2] = SkToU16(bounds.fTop) | (SkToU16(bounds.fBottom) << 16); | 502 builder[2] = SkToU16(bounds.fTop) | (SkToU16(bounds.fBottom) << 16); |
| 503 } | 503 } |
| 504 | 504 |
| 505 GrTexture* GrClipMaskManager::CreateAlphaClipMask(GrContext* context, | 505 sk_sp<GrTexture> GrClipMaskManager::CreateAlphaClipMask(GrContext* context, |
| 506 int32_t elementsGenID, | 506 int32_t elementsGenID, |
| 507 GrReducedClip::InitialState in
itialState, | 507 GrReducedClip::InitialSt
ate initialState, |
| 508 const GrReducedClip::ElementLi
st& elements, | 508 const GrReducedClip::Ele
mentList& elements, |
| 509 const SkVector& clipToMaskOffs
et, | 509 const SkVector& clipToMa
skOffset, |
| 510 const SkIRect& clipSpaceIBound
s) { | 510 const SkIRect& clipSpace
IBounds) { |
| 511 GrResourceProvider* resourceProvider = context->resourceProvider(); | 511 GrResourceProvider* resourceProvider = context->resourceProvider(); |
| 512 GrUniqueKey key; | 512 GrUniqueKey key; |
| 513 GetClipMaskKey(elementsGenID, clipSpaceIBounds, &key); | 513 GetClipMaskKey(elementsGenID, clipSpaceIBounds, &key); |
| 514 if (GrTexture* texture = resourceProvider->findAndRefTextureByUniqueKey(key)
) { | 514 if (GrTexture* texture = resourceProvider->findAndRefTextureByUniqueKey(key)
) { |
| 515 return texture; | 515 return sk_sp<GrTexture>(texture); |
| 516 } | 516 } |
| 517 | 517 |
| 518 // There's no texture in the cache. Let's try to allocate it then. | 518 // There's no texture in the cache. Let's try to allocate it then. |
| 519 GrSurfaceDesc desc; | 519 GrPixelConfig config = kRGBA_8888_GrPixelConfig; |
| 520 desc.fWidth = clipSpaceIBounds.width(); | |
| 521 desc.fHeight = clipSpaceIBounds.height(); | |
| 522 desc.fFlags = kRenderTarget_GrSurfaceFlag; | |
| 523 if (context->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) { | 520 if (context->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) { |
| 524 desc.fConfig = kAlpha_8_GrPixelConfig; | 521 config = kAlpha_8_GrPixelConfig; |
| 525 } else { | |
| 526 desc.fConfig = kRGBA_8888_GrPixelConfig; | |
| 527 } | 522 } |
| 528 | 523 |
| 529 SkAutoTUnref<GrTexture> texture(resourceProvider->createApproxTexture(desc,
0)); | 524 sk_sp<GrDrawContext> dc(context->newDrawContext(SkBackingFit::kApprox, |
| 530 if (!texture) { | 525 clipSpaceIBounds.width(), |
| 531 return nullptr; | 526 clipSpaceIBounds.height(), |
| 532 } | 527 config)); |
| 533 | |
| 534 texture->resourcePriv().setUniqueKey(key); | |
| 535 | |
| 536 sk_sp<GrDrawContext> dc(context->drawContext(sk_ref_sp(texture->asRenderTarg
et()))); | |
| 537 if (!dc) { | 528 if (!dc) { |
| 538 return nullptr; | 529 return nullptr; |
| 539 } | 530 } |
| 540 | 531 |
| 541 // The texture may be larger than necessary, this rect represents the part o
f the texture | 532 // The texture may be larger than necessary, this rect represents the part o
f the texture |
| 542 // we populate with a rasterization of the clip. | 533 // we populate with a rasterization of the clip. |
| 543 SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpa
ceIBounds.height()); | 534 SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpa
ceIBounds.height()); |
| 544 | 535 |
| 545 // The scratch texture that we are drawing into can be substantially larger
than the mask. Only | 536 // The scratch texture that we are drawing into can be substantially larger
than the mask. Only |
| 546 // clear the part that we care about. | 537 // clear the part that we care about. |
| 547 dc->clear(&maskSpaceIBounds, | 538 dc->clear(&maskSpaceIBounds, |
| 548 GrReducedClip::kAllIn_InitialState == initialState ? 0xffffffff :
0x00000000, | 539 GrReducedClip::kAllIn_InitialState == initialState ? 0xffffffff :
0x00000000, |
| 549 true); | 540 true); |
| 550 | 541 |
| 551 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip | 542 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip |
| 552 // space. | 543 // space. |
| 553 const SkMatrix translate = SkMatrix::MakeTrans(clipToMaskOffset.fX, clipToMa
skOffset.fY); | 544 const SkMatrix translate = SkMatrix::MakeTrans(clipToMaskOffset.fX, clipToMa
skOffset.fY); |
| 554 | 545 |
| 555 // It is important that we use maskSpaceIBounds as the stencil rect in the b
elow loop. | 546 // It is important that we use maskSpaceIBounds as the stencil rect in the b
elow loop. |
| 556 // The second pass that zeros the stencil buffer renders the rect maskSpaceI
Bounds so the first | 547 // The second pass that zeros the stencil buffer renders the rect maskSpaceI
Bounds so the first |
| 557 // pass must not set values outside of this bounds or stencil values outside
the rect won't be | 548 // pass must not set values outside of this bounds or stencil values outside
the rect won't be |
| 558 // cleared. | 549 // cleared. |
| 559 | 550 |
| 560 // walk through each clip element and perform its set op | 551 // walk through each clip element and perform its set op |
| 561 for (GrReducedClip::ElementList::Iter iter = elements.headIter(); iter.get()
; iter.next()) { | 552 for (GrReducedClip::ElementList::Iter iter = elements.headIter(); iter.get()
; iter.next()) { |
| 562 const Element* element = iter.get(); | 553 const Element* element = iter.get(); |
| 563 SkRegion::Op op = element->getOp(); | 554 SkRegion::Op op = element->getOp(); |
| 564 bool invert = element->isInverseFilled(); | 555 bool invert = element->isInverseFilled(); |
| 565 if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDiffere
nce_Op == op) { | 556 if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDiffere
nce_Op == op) { |
| 566 #ifdef SK_DEBUG | |
| 567 GrPathRenderer* pr = GetPathRenderer(context, | |
| 568 texture, translate, element); | |
| 569 if (Element::kRect_Type != element->getType() && !pr) { | |
| 570 // UseSWOnlyPath should now filter out all cases where gpu-side
mask merging would | |
| 571 // be performed (i.e., pr would be NULL for a non-rect path). | |
| 572 // See https://bug.skia.org/4519 for rationale and details. | |
| 573 SkASSERT(0); | |
| 574 } | |
| 575 #endif | |
| 576 | |
| 577 GrFixedClip clip(maskSpaceIBounds); | 557 GrFixedClip clip(maskSpaceIBounds); |
| 578 | 558 |
| 579 // draw directly into the result with the stencil set to make the pi
xels affected | 559 // draw directly into the result with the stencil set to make the pi
xels affected |
| 580 // by the clip shape be non-zero. | 560 // by the clip shape be non-zero. |
| 581 static constexpr GrUserStencilSettings kStencilInElement( | 561 static constexpr GrUserStencilSettings kStencilInElement( |
| 582 GrUserStencilSettings::StaticInit< | 562 GrUserStencilSettings::StaticInit< |
| 583 0xffff, | 563 0xffff, |
| 584 GrUserStencilTest::kAlways, | 564 GrUserStencilTest::kAlways, |
| 585 0xffff, | 565 0xffff, |
| 586 GrUserStencilOp::kReplace, | 566 GrUserStencilOp::kReplace, |
| 587 GrUserStencilOp::kReplace, | 567 GrUserStencilOp::kReplace, |
| 588 0xffff>() | 568 0xffff>() |
| 589 ); | 569 ); |
| 590 if (!stencil_element(dc.get(), clip, &kStencilInElement, | 570 if (!stencil_element(dc.get(), clip, &kStencilInElement, |
| 591 translate, element)) { | 571 translate, element)) { |
| 592 texture->resourcePriv().removeUniqueKey(); | |
| 593 return nullptr; | 572 return nullptr; |
| 594 } | 573 } |
| 595 | 574 |
| 596 // Draw to the exterior pixels (those with a zero stencil value). | 575 // Draw to the exterior pixels (those with a zero stencil value). |
| 597 static constexpr GrUserStencilSettings kDrawOutsideElement( | 576 static constexpr GrUserStencilSettings kDrawOutsideElement( |
| 598 GrUserStencilSettings::StaticInit< | 577 GrUserStencilSettings::StaticInit< |
| 599 0x0000, | 578 0x0000, |
| 600 GrUserStencilTest::kEqual, | 579 GrUserStencilTest::kEqual, |
| 601 0xffff, | 580 0xffff, |
| 602 GrUserStencilOp::kZero, | 581 GrUserStencilOp::kZero, |
| 603 GrUserStencilOp::kZero, | 582 GrUserStencilOp::kZero, |
| 604 0xffff>() | 583 0xffff>() |
| 605 ); | 584 ); |
| 606 if (!dc->drawContextPriv().drawAndStencilRect(clip, &kDrawOutsideEle
ment, | 585 if (!dc->drawContextPriv().drawAndStencilRect(clip, &kDrawOutsideEle
ment, |
| 607 op, !invert, false, | 586 op, !invert, false, |
| 608 translate, | 587 translate, |
| 609 SkRect::Make(clipSpace
IBounds))) { | 588 SkRect::Make(clipSpace
IBounds))) { |
| 610 texture->resourcePriv().removeUniqueKey(); | |
| 611 return nullptr; | 589 return nullptr; |
| 612 } | 590 } |
| 613 } else { | 591 } else { |
| 614 // all the remaining ops can just be directly draw into the accumula
tion buffer | 592 // all the remaining ops can just be directly draw into the accumula
tion buffer |
| 615 GrPaint paint; | 593 GrPaint paint; |
| 616 paint.setAntiAlias(element->isAA()); | 594 paint.setAntiAlias(element->isAA()); |
| 617 paint.setCoverageSetOpXPFactory(op, false); | 595 paint.setCoverageSetOpXPFactory(op, false); |
| 618 | 596 |
| 619 draw_element(dc.get(), GrNoClip(), paint, translate, element); | 597 draw_element(dc.get(), GrNoClip(), paint, translate, element); |
| 620 } | 598 } |
| 621 } | 599 } |
| 622 | 600 |
| 623 return texture.release(); | 601 sk_sp<GrTexture> texture(dc->asTexture()); |
| 602 SkASSERT(texture); |
| 603 texture->resourcePriv().setUniqueKey(key); |
| 604 return texture; |
| 624 } | 605 } |
| 625 | 606 |
| 626 //////////////////////////////////////////////////////////////////////////////// | 607 //////////////////////////////////////////////////////////////////////////////// |
| 627 // Create a 1-bit clip mask in the stencil buffer. 'devClipBounds' are in device | 608 // Create a 1-bit clip mask in the stencil buffer. 'devClipBounds' are in device |
| 628 // (as opposed to canvas) coordinates | 609 // (as opposed to canvas) coordinates |
| 629 bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt, | 610 bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt, |
| 630 int32_t elementsGenID, | 611 int32_t elementsGenID, |
| 631 GrReducedClip::InitialState initia
lState, | 612 GrReducedClip::InitialState initia
lState, |
| 632 const GrReducedClip::ElementList&
elements, | 613 const GrReducedClip::ElementList&
elements, |
| 633 const SkIRect& clipSpaceIBounds, | 614 const SkIRect& clipSpaceIBounds, |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 800 draw_non_aa_rect(fDrawTarget, pipelineBuilder, clip, GrColor
_WHITE, viewMatrix, | 781 draw_non_aa_rect(fDrawTarget, pipelineBuilder, clip, GrColor
_WHITE, viewMatrix, |
| 801 SkRect::Make(clipSpaceIBounds)); | 782 SkRect::Make(clipSpaceIBounds)); |
| 802 } | 783 } |
| 803 } | 784 } |
| 804 } | 785 } |
| 805 } | 786 } |
| 806 return true; | 787 return true; |
| 807 } | 788 } |
| 808 | 789 |
| 809 //////////////////////////////////////////////////////////////////////////////// | 790 //////////////////////////////////////////////////////////////////////////////// |
| 810 GrTexture* GrClipMaskManager::CreateSoftwareClipMask(GrContext* context, | 791 sk_sp<GrTexture> GrClipMaskManager::CreateSoftwareClipMask( |
| 811 int32_t elementsGenID, | 792 GrContext* context, |
| 812 GrReducedClip::InitialState
initialState, | 793 int32_t elementsGenID, |
| 813 const GrReducedClip::Elemen
tList& elements, | 794 GrReducedClip::InitialState
initialState, |
| 814 const SkVector& clipToMaskO
ffset, | 795 const GrReducedClip::Element
List& elements, |
| 815 const SkIRect& clipSpaceIBo
unds) { | 796 const SkVector& clipToMaskOf
fset, |
| 797 const SkIRect& clipSpaceIBou
nds) { |
| 816 GrUniqueKey key; | 798 GrUniqueKey key; |
| 817 GetClipMaskKey(elementsGenID, clipSpaceIBounds, &key); | 799 GetClipMaskKey(elementsGenID, clipSpaceIBounds, &key); |
| 818 GrResourceProvider* resourceProvider = context->resourceProvider(); | 800 GrResourceProvider* resourceProvider = context->resourceProvider(); |
| 819 if (GrTexture* texture = resourceProvider->findAndRefTextureByUniqueKey(key)
) { | 801 if (GrTexture* texture = resourceProvider->findAndRefTextureByUniqueKey(key)
) { |
| 820 return texture; | 802 return sk_sp<GrTexture>(texture); |
| 821 } | 803 } |
| 822 | 804 |
| 823 // The mask texture may be larger than necessary. We round out the clip spac
e bounds and pin | 805 // The mask texture may be larger than necessary. We round out the clip spac
e bounds and pin |
| 824 // the top left corner of the resulting rect to the top left of the texture. | 806 // the top left corner of the resulting rect to the top left of the texture. |
| 825 SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpa
ceIBounds.height()); | 807 SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpa
ceIBounds.height()); |
| 826 | 808 |
| 827 GrSWMaskHelper helper(context); | 809 GrSWMaskHelper helper(context); |
| 828 | 810 |
| 829 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip | 811 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip |
| 830 // space. | 812 // space. |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 866 helper.drawPath(path, GrStyle::SimpleFill(), op, element->isAA(), 0x
FF); | 848 helper.drawPath(path, GrStyle::SimpleFill(), op, element->isAA(), 0x
FF); |
| 867 } | 849 } |
| 868 } | 850 } |
| 869 | 851 |
| 870 // Allocate clip mask texture | 852 // Allocate clip mask texture |
| 871 GrSurfaceDesc desc; | 853 GrSurfaceDesc desc; |
| 872 desc.fWidth = clipSpaceIBounds.width(); | 854 desc.fWidth = clipSpaceIBounds.width(); |
| 873 desc.fHeight = clipSpaceIBounds.height(); | 855 desc.fHeight = clipSpaceIBounds.height(); |
| 874 desc.fConfig = kAlpha_8_GrPixelConfig; | 856 desc.fConfig = kAlpha_8_GrPixelConfig; |
| 875 | 857 |
| 876 GrTexture* result = context->resourceProvider()->createApproxTexture(desc, 0
); | 858 sk_sp<GrTexture> result(context->resourceProvider()->createApproxTexture(des
c, 0)); |
| 877 if (!result) { | 859 if (!result) { |
| 878 return nullptr; | 860 return nullptr; |
| 879 } | 861 } |
| 880 result->resourcePriv().setUniqueKey(key); | 862 result->resourcePriv().setUniqueKey(key); |
| 881 | 863 |
| 882 helper.toTexture(result); | 864 helper.toTexture(result.get()); |
| 883 | 865 |
| 884 return result; | 866 return result; |
| 885 } | 867 } |
| OLD | NEW |