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 |