| 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 sk_sp<GrTexture> result; | 373 SkAutoTUnref<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 = CreateSoftwareClipMask(this->getContext(), | 384 result.reset(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 = CreateAlphaClipMask(this->getContext(), | 391 result.reset(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.get(), rtSpaceM
askBounds)); | 406 out->fClipCoverageFP.reset(create_fp_for_mask(result, rtSpaceMaskBou
nds)); |
| 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 sk_sp<GrTexture> GrClipMaskManager::CreateAlphaClipMask(GrContext* context, | 505 GrTexture* GrClipMaskManager::CreateAlphaClipMask(GrContext* context, |
| 506 int32_t elementsGenID, | 506 int32_t elementsGenID, |
| 507 GrReducedClip::InitialSt
ate initialState, | 507 GrReducedClip::InitialState in
itialState, |
| 508 const GrReducedClip::Ele
mentList& elements, | 508 const GrReducedClip::ElementLi
st& elements, |
| 509 const SkVector& clipToMa
skOffset, | 509 const SkVector& clipToMaskOffs
et, |
| 510 const SkIRect& clipSpace
IBounds) { | 510 const SkIRect& clipSpaceIBound
s) { |
| 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 sk_ref_sp(texture); | 515 return 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 GrPixelConfig config = kRGBA_8888_GrPixelConfig; | 519 GrSurfaceDesc desc; |
| 520 desc.fWidth = clipSpaceIBounds.width(); |
| 521 desc.fHeight = clipSpaceIBounds.height(); |
| 522 desc.fFlags = kRenderTarget_GrSurfaceFlag; |
| 520 if (context->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) { | 523 if (context->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) { |
| 521 config = kAlpha_8_GrPixelConfig; | 524 desc.fConfig = kAlpha_8_GrPixelConfig; |
| 525 } else { |
| 526 desc.fConfig = kRGBA_8888_GrPixelConfig; |
| 522 } | 527 } |
| 523 | 528 |
| 524 sk_sp<GrDrawContext> dc(context->newDrawContext(SkBackingFit::kApprox, | 529 SkAutoTUnref<GrTexture> texture(resourceProvider->createApproxTexture(desc,
0)); |
| 525 clipSpaceIBounds.width(), | 530 if (!texture) { |
| 526 clipSpaceIBounds.height(), | 531 return nullptr; |
| 527 config)); | 532 } |
| 533 |
| 534 texture->resourcePriv().setUniqueKey(key); |
| 535 |
| 536 sk_sp<GrDrawContext> dc(context->drawContext(sk_ref_sp(texture->asRenderTarg
et()))); |
| 528 if (!dc) { | 537 if (!dc) { |
| 529 return nullptr; | 538 return nullptr; |
| 530 } | 539 } |
| 531 | 540 |
| 532 // The texture may be larger than necessary, this rect represents the part o
f the texture | 541 // The texture may be larger than necessary, this rect represents the part o
f the texture |
| 533 // we populate with a rasterization of the clip. | 542 // we populate with a rasterization of the clip. |
| 534 SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpa
ceIBounds.height()); | 543 SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpa
ceIBounds.height()); |
| 535 | 544 |
| 536 // The scratch texture that we are drawing into can be substantially larger
than the mask. Only | 545 // The scratch texture that we are drawing into can be substantially larger
than the mask. Only |
| 537 // clear the part that we care about. | 546 // clear the part that we care about. |
| 538 dc->clear(&maskSpaceIBounds, | 547 dc->clear(&maskSpaceIBounds, |
| 539 GrReducedClip::kAllIn_InitialState == initialState ? 0xffffffff :
0x00000000, | 548 GrReducedClip::kAllIn_InitialState == initialState ? 0xffffffff :
0x00000000, |
| 540 true); | 549 true); |
| 541 | 550 |
| 542 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip | 551 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip |
| 543 // space. | 552 // space. |
| 544 const SkMatrix translate = SkMatrix::MakeTrans(clipToMaskOffset.fX, clipToMa
skOffset.fY); | 553 const SkMatrix translate = SkMatrix::MakeTrans(clipToMaskOffset.fX, clipToMa
skOffset.fY); |
| 545 | 554 |
| 546 // It is important that we use maskSpaceIBounds as the stencil rect in the b
elow loop. | 555 // It is important that we use maskSpaceIBounds as the stencil rect in the b
elow loop. |
| 547 // The second pass that zeros the stencil buffer renders the rect maskSpaceI
Bounds so the first | 556 // The second pass that zeros the stencil buffer renders the rect maskSpaceI
Bounds so the first |
| 548 // pass must not set values outside of this bounds or stencil values outside
the rect won't be | 557 // pass must not set values outside of this bounds or stencil values outside
the rect won't be |
| 549 // cleared. | 558 // cleared. |
| 550 | 559 |
| 551 // walk through each clip element and perform its set op | 560 // walk through each clip element and perform its set op |
| 552 for (GrReducedClip::ElementList::Iter iter = elements.headIter(); iter.get()
; iter.next()) { | 561 for (GrReducedClip::ElementList::Iter iter = elements.headIter(); iter.get()
; iter.next()) { |
| 553 const Element* element = iter.get(); | 562 const Element* element = iter.get(); |
| 554 SkRegion::Op op = element->getOp(); | 563 SkRegion::Op op = element->getOp(); |
| 555 bool invert = element->isInverseFilled(); | 564 bool invert = element->isInverseFilled(); |
| 556 if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDiffere
nce_Op == op) { | 565 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 |
| 557 GrFixedClip clip(maskSpaceIBounds); | 577 GrFixedClip clip(maskSpaceIBounds); |
| 558 | 578 |
| 559 // draw directly into the result with the stencil set to make the pi
xels affected | 579 // draw directly into the result with the stencil set to make the pi
xels affected |
| 560 // by the clip shape be non-zero. | 580 // by the clip shape be non-zero. |
| 561 static constexpr GrUserStencilSettings kStencilInElement( | 581 static constexpr GrUserStencilSettings kStencilInElement( |
| 562 GrUserStencilSettings::StaticInit< | 582 GrUserStencilSettings::StaticInit< |
| 563 0xffff, | 583 0xffff, |
| 564 GrUserStencilTest::kAlways, | 584 GrUserStencilTest::kAlways, |
| 565 0xffff, | 585 0xffff, |
| 566 GrUserStencilOp::kReplace, | 586 GrUserStencilOp::kReplace, |
| 567 GrUserStencilOp::kReplace, | 587 GrUserStencilOp::kReplace, |
| 568 0xffff>() | 588 0xffff>() |
| 569 ); | 589 ); |
| 570 if (!stencil_element(dc.get(), clip, &kStencilInElement, | 590 if (!stencil_element(dc.get(), clip, &kStencilInElement, |
| 571 translate, element)) { | 591 translate, element)) { |
| 592 texture->resourcePriv().removeUniqueKey(); |
| 572 return nullptr; | 593 return nullptr; |
| 573 } | 594 } |
| 574 | 595 |
| 575 // Draw to the exterior pixels (those with a zero stencil value). | 596 // Draw to the exterior pixels (those with a zero stencil value). |
| 576 static constexpr GrUserStencilSettings kDrawOutsideElement( | 597 static constexpr GrUserStencilSettings kDrawOutsideElement( |
| 577 GrUserStencilSettings::StaticInit< | 598 GrUserStencilSettings::StaticInit< |
| 578 0x0000, | 599 0x0000, |
| 579 GrUserStencilTest::kEqual, | 600 GrUserStencilTest::kEqual, |
| 580 0xffff, | 601 0xffff, |
| 581 GrUserStencilOp::kZero, | 602 GrUserStencilOp::kZero, |
| 582 GrUserStencilOp::kZero, | 603 GrUserStencilOp::kZero, |
| 583 0xffff>() | 604 0xffff>() |
| 584 ); | 605 ); |
| 585 if (!dc->drawContextPriv().drawAndStencilRect(clip, &kDrawOutsideEle
ment, | 606 if (!dc->drawContextPriv().drawAndStencilRect(clip, &kDrawOutsideEle
ment, |
| 586 op, !invert, false, | 607 op, !invert, false, |
| 587 translate, | 608 translate, |
| 588 SkRect::Make(clipSpace
IBounds))) { | 609 SkRect::Make(clipSpace
IBounds))) { |
| 610 texture->resourcePriv().removeUniqueKey(); |
| 589 return nullptr; | 611 return nullptr; |
| 590 } | 612 } |
| 591 } else { | 613 } else { |
| 592 // all the remaining ops can just be directly draw into the accumula
tion buffer | 614 // all the remaining ops can just be directly draw into the accumula
tion buffer |
| 593 GrPaint paint; | 615 GrPaint paint; |
| 594 paint.setAntiAlias(element->isAA()); | 616 paint.setAntiAlias(element->isAA()); |
| 595 paint.setCoverageSetOpXPFactory(op, false); | 617 paint.setCoverageSetOpXPFactory(op, false); |
| 596 | 618 |
| 597 draw_element(dc.get(), GrNoClip(), paint, translate, element); | 619 draw_element(dc.get(), GrNoClip(), paint, translate, element); |
| 598 } | 620 } |
| 599 } | 621 } |
| 600 | 622 |
| 601 sk_sp<GrTexture> texture(dc->asTexture()); | 623 return texture.release(); |
| 602 SkASSERT(texture); | |
| 603 texture->resourcePriv().setUniqueKey(key); | |
| 604 return texture; | |
| 605 } | 624 } |
| 606 | 625 |
| 607 //////////////////////////////////////////////////////////////////////////////// | 626 //////////////////////////////////////////////////////////////////////////////// |
| 608 // Create a 1-bit clip mask in the stencil buffer. 'devClipBounds' are in device | 627 // Create a 1-bit clip mask in the stencil buffer. 'devClipBounds' are in device |
| 609 // (as opposed to canvas) coordinates | 628 // (as opposed to canvas) coordinates |
| 610 bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt, | 629 bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt, |
| 611 int32_t elementsGenID, | 630 int32_t elementsGenID, |
| 612 GrReducedClip::InitialState initia
lState, | 631 GrReducedClip::InitialState initia
lState, |
| 613 const GrReducedClip::ElementList&
elements, | 632 const GrReducedClip::ElementList&
elements, |
| 614 const SkIRect& clipSpaceIBounds, | 633 const SkIRect& clipSpaceIBounds, |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 781 draw_non_aa_rect(fDrawTarget, pipelineBuilder, clip, GrColor
_WHITE, viewMatrix, | 800 draw_non_aa_rect(fDrawTarget, pipelineBuilder, clip, GrColor
_WHITE, viewMatrix, |
| 782 SkRect::Make(clipSpaceIBounds)); | 801 SkRect::Make(clipSpaceIBounds)); |
| 783 } | 802 } |
| 784 } | 803 } |
| 785 } | 804 } |
| 786 } | 805 } |
| 787 return true; | 806 return true; |
| 788 } | 807 } |
| 789 | 808 |
| 790 //////////////////////////////////////////////////////////////////////////////// | 809 //////////////////////////////////////////////////////////////////////////////// |
| 791 sk_sp<GrTexture> GrClipMaskManager::CreateSoftwareClipMask( | 810 GrTexture* GrClipMaskManager::CreateSoftwareClipMask(GrContext* context, |
| 792 GrContext* context, | 811 int32_t elementsGenID, |
| 793 int32_t elementsGenID, | 812 GrReducedClip::InitialState
initialState, |
| 794 GrReducedClip::InitialState
initialState, | 813 const GrReducedClip::Elemen
tList& elements, |
| 795 const GrReducedClip::Element
List& elements, | 814 const SkVector& clipToMaskO
ffset, |
| 796 const SkVector& clipToMaskOf
fset, | 815 const SkIRect& clipSpaceIBo
unds) { |
| 797 const SkIRect& clipSpaceIBou
nds) { | |
| 798 GrUniqueKey key; | 816 GrUniqueKey key; |
| 799 GetClipMaskKey(elementsGenID, clipSpaceIBounds, &key); | 817 GetClipMaskKey(elementsGenID, clipSpaceIBounds, &key); |
| 800 GrResourceProvider* resourceProvider = context->resourceProvider(); | 818 GrResourceProvider* resourceProvider = context->resourceProvider(); |
| 801 if (GrTexture* texture = resourceProvider->findAndRefTextureByUniqueKey(key)
) { | 819 if (GrTexture* texture = resourceProvider->findAndRefTextureByUniqueKey(key)
) { |
| 802 return sk_ref_sp(texture); | 820 return texture; |
| 803 } | 821 } |
| 804 | 822 |
| 805 // The mask texture may be larger than necessary. We round out the clip spac
e bounds and pin | 823 // The mask texture may be larger than necessary. We round out the clip spac
e bounds and pin |
| 806 // the top left corner of the resulting rect to the top left of the texture. | 824 // the top left corner of the resulting rect to the top left of the texture. |
| 807 SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpa
ceIBounds.height()); | 825 SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpa
ceIBounds.height()); |
| 808 | 826 |
| 809 GrSWMaskHelper helper(context); | 827 GrSWMaskHelper helper(context); |
| 810 | 828 |
| 811 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip | 829 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip |
| 812 // space. | 830 // space. |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 848 helper.drawPath(path, GrStyle::SimpleFill(), op, element->isAA(), 0x
FF); | 866 helper.drawPath(path, GrStyle::SimpleFill(), op, element->isAA(), 0x
FF); |
| 849 } | 867 } |
| 850 } | 868 } |
| 851 | 869 |
| 852 // Allocate clip mask texture | 870 // Allocate clip mask texture |
| 853 GrSurfaceDesc desc; | 871 GrSurfaceDesc desc; |
| 854 desc.fWidth = clipSpaceIBounds.width(); | 872 desc.fWidth = clipSpaceIBounds.width(); |
| 855 desc.fHeight = clipSpaceIBounds.height(); | 873 desc.fHeight = clipSpaceIBounds.height(); |
| 856 desc.fConfig = kAlpha_8_GrPixelConfig; | 874 desc.fConfig = kAlpha_8_GrPixelConfig; |
| 857 | 875 |
| 858 sk_sp<GrTexture> result(context->resourceProvider()->createApproxTexture(des
c, 0)); | 876 GrTexture* result = context->resourceProvider()->createApproxTexture(desc, 0
); |
| 859 if (!result) { | 877 if (!result) { |
| 860 return nullptr; | 878 return nullptr; |
| 861 } | 879 } |
| 862 result->resourcePriv().setUniqueKey(key); | 880 result->resourcePriv().setUniqueKey(key); |
| 863 | 881 |
| 864 helper.toTexture(result.get()); | 882 helper.toTexture(result); |
| 865 | 883 |
| 866 return result; | 884 return result; |
| 867 } | 885 } |
| OLD | NEW |