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 |