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 "GrClipStackClip.h" | 8 #include "GrClipStackClip.h" |
9 | 9 |
10 #include "GrAppliedClip.h" | 10 #include "GrAppliedClip.h" |
| 11 #include "GrContextPriv.h" |
11 #include "GrDrawingManager.h" | 12 #include "GrDrawingManager.h" |
12 #include "GrDrawContextPriv.h" | 13 #include "GrDrawContextPriv.h" |
13 #include "GrFixedClip.h" | 14 #include "GrFixedClip.h" |
14 #include "GrGpuResourcePriv.h" | 15 #include "GrGpuResourcePriv.h" |
15 #include "GrRenderTargetPriv.h" | 16 #include "GrRenderTargetPriv.h" |
16 #include "GrStencilAttachment.h" | 17 #include "GrStencilAttachment.h" |
17 #include "GrSWMaskHelper.h" | 18 #include "GrSWMaskHelper.h" |
18 #include "effects/GrConvexPolyEffect.h" | 19 #include "effects/GrConvexPolyEffect.h" |
19 #include "effects/GrRRectEffect.h" | 20 #include "effects/GrRRectEffect.h" |
20 #include "effects/GrTextureDomain.h" | 21 #include "effects/GrTextureDomain.h" |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
143 GrShape shape(path, GrStyle::SimpleFill()); | 144 GrShape shape(path, GrStyle::SimpleFill()); |
144 GrPathRenderer::CanDrawPathArgs canDrawArgs; | 145 GrPathRenderer::CanDrawPathArgs canDrawArgs; |
145 canDrawArgs.fShaderCaps = context->caps()->shaderCaps(); | 146 canDrawArgs.fShaderCaps = context->caps()->shaderCaps(); |
146 canDrawArgs.fViewMatrix = &viewMatrix; | 147 canDrawArgs.fViewMatrix = &viewMatrix; |
147 canDrawArgs.fShape = &shape; | 148 canDrawArgs.fShape = &shape; |
148 canDrawArgs.fAntiAlias = element->isAA(); | 149 canDrawArgs.fAntiAlias = element->isAA(); |
149 canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings; | 150 canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings; |
150 canDrawArgs.fIsStencilBufferMSAA = drawContext->isStencilBufferMultisamp
led(); | 151 canDrawArgs.fIsStencilBufferMSAA = drawContext->isStencilBufferMultisamp
led(); |
151 | 152 |
152 // the 'false' parameter disallows use of the SW path renderer | 153 // the 'false' parameter disallows use of the SW path renderer |
153 GrPathRenderer* pr = context->drawingManager()->getPathRenderer(canDrawA
rgs, false, type); | 154 GrPathRenderer* pr = |
| 155 context->contextPriv().drawingManager()->getPathRenderer(canDrawArgs
, false, type); |
154 if (prOut) { | 156 if (prOut) { |
155 *prOut = pr; | 157 *prOut = pr; |
156 } | 158 } |
157 return SkToBool(!pr); | 159 return SkToBool(!pr); |
158 } | 160 } |
159 } | 161 } |
160 | 162 |
161 /* | 163 /* |
162 * This method traverses the clip stack to see if the GrSoftwarePathRenderer | 164 * This method traverses the clip stack to see if the GrSoftwarePathRenderer |
163 * will be used on any element. If so, it returns true to indicate that the | 165 * will be used on any element. If so, it returns true to indicate that the |
164 * entire clip should be rendered in SW and then uploaded en masse to the gpu. | 166 * entire clip should be rendered in SW and then uploaded en masse to the gpu. |
165 */ | 167 */ |
166 bool GrClipStackClip::UseSWOnlyPath(GrContext* context, | 168 bool GrClipStackClip::UseSWOnlyPath(GrContext* context, |
167 bool hasUserStencilSettings, | 169 bool hasUserStencilSettings, |
168 const GrDrawContext* drawContext, | 170 const GrDrawContext* drawContext, |
169 const SkVector& clipToMaskOffset, | 171 const GrReducedClip& reducedClip) { |
170 const ElementList& elements) { | |
171 // TODO: generalize this function so that when | 172 // TODO: generalize this function so that when |
172 // a clip gets complex enough it can just be done in SW regardless | 173 // a clip gets complex enough it can just be done in SW regardless |
173 // of whether it would invoke the GrSoftwarePathRenderer. | 174 // of whether it would invoke the GrSoftwarePathRenderer. |
174 | 175 |
175 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip | 176 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip |
176 // space. | 177 // space. |
177 const SkMatrix translate = SkMatrix::MakeTrans(clipToMaskOffset.fX, clipToMa
skOffset.fY); | 178 SkMatrix translate; |
| 179 translate.setTranslate(SkIntToScalar(-reducedClip.left()), SkIntToScalar(-re
ducedClip.top())); |
178 | 180 |
179 for (ElementList::Iter iter(elements); iter.get(); iter.next()) { | 181 for (ElementList::Iter iter(reducedClip.elements()); iter.get(); iter.next()
) { |
180 const Element* element = iter.get(); | 182 const Element* element = iter.get(); |
181 | 183 |
182 SkRegion::Op op = element->getOp(); | 184 SkRegion::Op op = element->getOp(); |
183 bool invert = element->isInverseFilled(); | 185 bool invert = element->isInverseFilled(); |
184 bool needsStencil = invert || | 186 bool needsStencil = invert || |
185 SkRegion::kIntersect_Op == op || SkRegion::kReverseD
ifference_Op == op; | 187 SkRegion::kIntersect_Op == op || SkRegion::kReverseD
ifference_Op == op; |
186 | 188 |
187 if (PathNeedsSWRenderer(context, hasUserStencilSettings, | 189 if (PathNeedsSWRenderer(context, hasUserStencilSettings, |
188 drawContext, translate, element, nullptr, needsS
tencil)) { | 190 drawContext, translate, element, nullptr, needsS
tencil)) { |
189 return true; | 191 return true; |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
344 get_analytic_clip_processor(reducedClip.elements(), disallowAnalytic
AA, | 346 get_analytic_clip_processor(reducedClip.elements(), disallowAnalytic
AA, |
345 {-clipX, -clipY}, devBounds, &clipFP)) { | 347 {-clipX, -clipY}, devBounds, &clipFP)) { |
346 out->addCoverageFP(std::move(clipFP)); | 348 out->addCoverageFP(std::move(clipFP)); |
347 return true; | 349 return true; |
348 } | 350 } |
349 } | 351 } |
350 | 352 |
351 // If the stencil buffer is multisampled we can use it to do everything. | 353 // If the stencil buffer is multisampled we can use it to do everything. |
352 if (!drawContext->isStencilBufferMultisampled() && reducedClip.requiresAA())
{ | 354 if (!drawContext->isStencilBufferMultisampled() && reducedClip.requiresAA())
{ |
353 sk_sp<GrTexture> result; | 355 sk_sp<GrTexture> result; |
354 | 356 if (UseSWOnlyPath(context, hasUserStencilSettings, drawContext, reducedC
lip)) { |
355 // The top-left of the mask corresponds to the top-left corner of the bo
unds. | |
356 SkVector clipToMaskOffset = { | |
357 SkIntToScalar(-reducedClip.left()), | |
358 SkIntToScalar(-reducedClip.top()) | |
359 }; | |
360 | |
361 if (UseSWOnlyPath(context, hasUserStencilSettings, drawContext, | |
362 clipToMaskOffset, reducedClip.elements())) { | |
363 // The clip geometry is complex enough that it will be more efficien
t to create it | 357 // The clip geometry is complex enough that it will be more efficien
t to create it |
364 // entirely in software | 358 // entirely in software |
365 result = CreateSoftwareClipMask(context->textureProvider(), reducedC
lip, | 359 result = CreateSoftwareClipMask(context->textureProvider(), reducedC
lip); |
366 clipToMaskOffset); | |
367 } else { | 360 } else { |
368 result = CreateAlphaClipMask(context, reducedClip, clipToMaskOffset)
; | 361 result = CreateAlphaClipMask(context, reducedClip); |
369 // If createAlphaClipMask fails it means UseSWOnlyPath has a bug | 362 // If createAlphaClipMask fails it means UseSWOnlyPath has a bug |
370 SkASSERT(result); | 363 SkASSERT(result); |
371 } | 364 } |
372 | 365 |
373 if (result) { | 366 if (result) { |
374 // The mask's top left coord should be pinned to the rounded-out top
left corner of | 367 // The mask's top left coord should be pinned to the rounded-out top
left corner of |
375 // clipSpace bounds. We determine the mask's position WRT to the ren
der target here. | 368 // clipSpace bounds. We determine the mask's position WRT to the ren
der target here. |
376 SkIRect rtSpaceMaskBounds = reducedClip.ibounds(); | 369 SkIRect rtSpaceMaskBounds = reducedClip.ibounds(); |
377 rtSpaceMaskBounds.offset(-fOrigin); | 370 rtSpaceMaskBounds.offset(-fOrigin); |
378 out->addCoverageFP(create_fp_for_mask(result.get(), rtSpaceMaskBound
s)); | 371 out->addCoverageFP(create_fp_for_mask(result.get(), rtSpaceMaskBound
s)); |
379 return true; | 372 return true; |
380 } | 373 } |
381 // if alpha clip mask creation fails fall through to the non-AA code pat
hs | 374 // if alpha clip mask creation fails fall through to the non-AA code pat
hs |
382 } | 375 } |
383 | 376 |
384 // use the stencil clip if we can't represent the clip as a rectangle. | 377 // use the stencil clip if we can't represent the clip as a rectangle. |
385 SkIPoint clipSpaceToStencilSpaceOffset = -fOrigin; | 378 // TODO: these need to be swapped over to using a StencilAttachmentProxy |
386 CreateStencilClipMask(context, drawContext, reducedClip, clipSpaceToStencilS
paceOffset); | 379 GrStencilAttachment* stencilAttachment = |
| 380 context->resourceProvider()->attachStencilAttachment(drawContext->access
RenderTarget()); |
| 381 if (nullptr == stencilAttachment) { |
| 382 SkDebugf("WARNING: failed to attach stencil buffer for clip mask. Clip w
ill be ignored.\n"); |
| 383 return true; |
| 384 } |
| 385 |
| 386 if (stencilAttachment->mustRenderClip(reducedClip.elementsGenID(), reducedCl
ip.ibounds(), |
| 387 fOrigin)) { |
| 388 reducedClip.drawStencilClipMask(context, drawContext, fOrigin); |
| 389 stencilAttachment->setLastClip(reducedClip.elementsGenID(), reducedClip.
ibounds(), |
| 390 fOrigin); |
| 391 } |
387 out->addStencilClip(); | 392 out->addStencilClip(); |
388 return true; | 393 return true; |
389 } | 394 } |
390 | 395 |
391 static bool stencil_element(GrDrawContext* dc, | |
392 const GrFixedClip& clip, | |
393 const GrUserStencilSettings* ss, | |
394 const SkMatrix& viewMatrix, | |
395 const SkClipStack::Element* element) { | |
396 | |
397 // TODO: Draw rrects directly here. | |
398 switch (element->getType()) { | |
399 case Element::kEmpty_Type: | |
400 SkDEBUGFAIL("Should never get here with an empty element."); | |
401 break; | |
402 case Element::kRect_Type: | |
403 return dc->drawContextPriv().drawAndStencilRect(clip, ss, | |
404 element->getOp(), | |
405 element->isInverseFi
lled(), | |
406 element->isAA(), | |
407 viewMatrix, element-
>getRect()); | |
408 break; | |
409 default: { | |
410 SkPath path; | |
411 element->asPath(&path); | |
412 if (path.isInverseFillType()) { | |
413 path.toggleInverseFillType(); | |
414 } | |
415 | |
416 return dc->drawContextPriv().drawAndStencilPath(clip, ss, | |
417 element->getOp(), | |
418 element->isInverseFi
lled(), | |
419 element->isAA(), vie
wMatrix, path); | |
420 break; | |
421 } | |
422 } | |
423 | |
424 return false; | |
425 } | |
426 | |
427 static void draw_element(GrDrawContext* dc, | |
428 const GrClip& clip, // TODO: can this just always be Wi
deOpen? | |
429 const GrPaint &paint, | |
430 const SkMatrix& viewMatrix, | |
431 const SkClipStack::Element* element) { | |
432 | |
433 // TODO: Draw rrects directly here. | |
434 switch (element->getType()) { | |
435 case Element::kEmpty_Type: | |
436 SkDEBUGFAIL("Should never get here with an empty element."); | |
437 break; | |
438 case Element::kRect_Type: | |
439 dc->drawRect(clip, paint, viewMatrix, element->getRect()); | |
440 break; | |
441 default: { | |
442 SkPath path; | |
443 element->asPath(&path); | |
444 if (path.isInverseFillType()) { | |
445 path.toggleInverseFillType(); | |
446 } | |
447 | |
448 dc->drawPath(clip, paint, viewMatrix, path, GrStyle::SimpleFill()); | |
449 break; | |
450 } | |
451 } | |
452 } | |
453 | |
454 //////////////////////////////////////////////////////////////////////////////// | 396 //////////////////////////////////////////////////////////////////////////////// |
455 // Create a 8-bit clip mask in alpha | 397 // Create a 8-bit clip mask in alpha |
456 | 398 |
457 static void GetClipMaskKey(int32_t clipGenID, const SkIRect& bounds, GrUniqueKey
* key) { | 399 static void GetClipMaskKey(int32_t clipGenID, const SkIRect& bounds, GrUniqueKey
* key) { |
458 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); | 400 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); |
459 GrUniqueKey::Builder builder(key, kDomain, 3); | 401 GrUniqueKey::Builder builder(key, kDomain, 3); |
460 builder[0] = clipGenID; | 402 builder[0] = clipGenID; |
461 builder[1] = SkToU16(bounds.fLeft) | (SkToU16(bounds.fRight) << 16); | 403 builder[1] = SkToU16(bounds.fLeft) | (SkToU16(bounds.fRight) << 16); |
462 builder[2] = SkToU16(bounds.fTop) | (SkToU16(bounds.fBottom) << 16); | 404 builder[2] = SkToU16(bounds.fTop) | (SkToU16(bounds.fBottom) << 16); |
463 } | 405 } |
464 | 406 |
465 sk_sp<GrTexture> GrClipStackClip::CreateAlphaClipMask(GrContext* context, | 407 sk_sp<GrTexture> GrClipStackClip::CreateAlphaClipMask(GrContext* context, |
466 const GrReducedClip& reduc
edClip, | 408 const GrReducedClip& reduc
edClip) { |
467 const SkVector& clipToMask
Offset) { | |
468 GrResourceProvider* resourceProvider = context->resourceProvider(); | 409 GrResourceProvider* resourceProvider = context->resourceProvider(); |
469 GrUniqueKey key; | 410 GrUniqueKey key; |
470 GetClipMaskKey(reducedClip.elementsGenID(), reducedClip.ibounds(), &key); | 411 GetClipMaskKey(reducedClip.elementsGenID(), reducedClip.ibounds(), &key); |
471 if (GrTexture* texture = resourceProvider->findAndRefTextureByUniqueKey(key)
) { | 412 if (GrTexture* texture = resourceProvider->findAndRefTextureByUniqueKey(key)
) { |
472 return sk_sp<GrTexture>(texture); | 413 return sk_sp<GrTexture>(texture); |
473 } | 414 } |
474 | 415 |
475 // There's no texture in the cache. Let's try to allocate it then. | 416 // There's no texture in the cache. Let's try to allocate it then. |
476 GrPixelConfig config = kRGBA_8888_GrPixelConfig; | 417 GrPixelConfig config = kRGBA_8888_GrPixelConfig; |
477 if (context->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) { | 418 if (context->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) { |
478 config = kAlpha_8_GrPixelConfig; | 419 config = kAlpha_8_GrPixelConfig; |
479 } | 420 } |
480 | 421 |
481 sk_sp<GrDrawContext> dc(context->makeDrawContext(SkBackingFit::kApprox, | 422 sk_sp<GrDrawContext> dc(context->makeDrawContext(SkBackingFit::kApprox, |
482 reducedClip.width(), | 423 reducedClip.width(), |
483 reducedClip.height(), | 424 reducedClip.height(), |
484 config, nullptr)); | 425 config, nullptr)); |
485 if (!dc) { | 426 if (!dc) { |
486 return nullptr; | 427 return nullptr; |
487 } | 428 } |
488 | |
489 // The texture may be larger than necessary, this rect represents the part o
f the texture | |
490 // we populate with a rasterization of the clip. | |
491 SkIRect maskSpaceIBounds = SkIRect::MakeWH(reducedClip.width(), reducedClip.
height()); | |
492 GrFixedClip clip(maskSpaceIBounds); | |
493 | 429 |
494 // The scratch texture that we are drawing into can be substantially larger
than the mask. Only | 430 if (!reducedClip.drawAlphaClipMask(dc.get())) { |
495 // clear the part that we care about. | 431 return nullptr; |
496 GrColor initialCoverage = InitialState::kAllIn == reducedClip.initialState()
? -1 : 0; | |
497 dc->drawContextPriv().clear(clip, initialCoverage, true); | |
498 | |
499 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip | |
500 // space. | |
501 const SkMatrix translate = SkMatrix::MakeTrans(clipToMaskOffset.fX, clipToMa
skOffset.fY); | |
502 | |
503 // It is important that we use maskSpaceIBounds as the stencil rect in the b
elow loop. | |
504 // The second pass that zeros the stencil buffer renders the rect maskSpaceI
Bounds so the first | |
505 // pass must not set values outside of this bounds or stencil values outside
the rect won't be | |
506 // cleared. | |
507 | |
508 // walk through each clip element and perform its set op | |
509 for (ElementList::Iter iter(reducedClip.elements()); iter.get(); iter.next()
) { | |
510 const Element* element = iter.get(); | |
511 SkRegion::Op op = element->getOp(); | |
512 bool invert = element->isInverseFilled(); | |
513 if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDiffere
nce_Op == op) { | |
514 // draw directly into the result with the stencil set to make the pi
xels affected | |
515 // by the clip shape be non-zero. | |
516 static constexpr GrUserStencilSettings kStencilInElement( | |
517 GrUserStencilSettings::StaticInit< | |
518 0xffff, | |
519 GrUserStencilTest::kAlways, | |
520 0xffff, | |
521 GrUserStencilOp::kReplace, | |
522 GrUserStencilOp::kReplace, | |
523 0xffff>() | |
524 ); | |
525 if (!stencil_element(dc.get(), clip, &kStencilInElement, | |
526 translate, element)) { | |
527 return nullptr; | |
528 } | |
529 | |
530 // Draw to the exterior pixels (those with a zero stencil value). | |
531 static constexpr GrUserStencilSettings kDrawOutsideElement( | |
532 GrUserStencilSettings::StaticInit< | |
533 0x0000, | |
534 GrUserStencilTest::kEqual, | |
535 0xffff, | |
536 GrUserStencilOp::kZero, | |
537 GrUserStencilOp::kZero, | |
538 0xffff>() | |
539 ); | |
540 if (!dc->drawContextPriv().drawAndStencilRect(clip, &kDrawOutsideEle
ment, | |
541 op, !invert, false, | |
542 translate, | |
543 SkRect::Make(reducedCl
ip.ibounds()))) { | |
544 return nullptr; | |
545 } | |
546 } else { | |
547 // all the remaining ops can just be directly draw into the accumula
tion buffer | |
548 GrPaint paint; | |
549 paint.setAntiAlias(element->isAA()); | |
550 paint.setCoverageSetOpXPFactory(op, false); | |
551 | |
552 draw_element(dc.get(), clip, paint, translate, element); | |
553 } | |
554 } | 432 } |
555 | 433 |
556 sk_sp<GrTexture> texture(dc->asTexture()); | 434 sk_sp<GrTexture> texture(dc->asTexture()); |
557 SkASSERT(texture); | 435 SkASSERT(texture); |
558 texture->resourcePriv().setUniqueKey(key); | 436 texture->resourcePriv().setUniqueKey(key); |
559 return texture; | 437 return texture; |
560 } | 438 } |
561 | 439 |
562 //////////////////////////////////////////////////////////////////////////////// | |
563 // Create a 1-bit clip mask in the stencil buffer. | |
564 | |
565 class StencilClip final : public GrClip { | |
566 public: | |
567 StencilClip(const SkIRect& scissorRect) : fFixedClip(scissorRect) {} | |
568 const GrFixedClip& fixedClip() const { return fFixedClip; } | |
569 | |
570 private: | |
571 bool quickContains(const SkRect&) const final { | |
572 return false; | |
573 } | |
574 void getConservativeBounds(int width, int height, SkIRect* devResult, bool*
iior) const final { | |
575 fFixedClip.getConservativeBounds(width, height, devResult, iior); | |
576 } | |
577 bool isRRect(const SkRect& rtBounds, SkRRect* rr, bool* aa) const final { | |
578 return false; | |
579 } | |
580 bool apply(GrContext* context, GrDrawContext* drawContext, bool useHWAA, | |
581 bool hasUserStencilSettings, GrAppliedClip* out) const final { | |
582 if (!fFixedClip.apply(context, drawContext, useHWAA, hasUserStencilSetti
ngs, out)) { | |
583 return false; | |
584 } | |
585 out->addStencilClip(); | |
586 return true; | |
587 } | |
588 | |
589 GrFixedClip fFixedClip; | |
590 | |
591 typedef GrClip INHERITED; | |
592 }; | |
593 | |
594 bool GrClipStackClip::CreateStencilClipMask(GrContext* context, | |
595 GrDrawContext* drawContext, | |
596 const GrReducedClip& reducedClip, | |
597 const SkIPoint& clipSpaceToStencilOf
fset) { | |
598 SkASSERT(drawContext); | |
599 | |
600 GrStencilAttachment* stencilAttachment = context->resourceProvider()->attach
StencilAttachment( | |
601 drawContext->accessRenderTar
get()); | |
602 if (nullptr == stencilAttachment) { | |
603 return false; | |
604 } | |
605 | |
606 // TODO: these need to be swapped over to using a StencilAttachmentProxy | |
607 if (stencilAttachment->mustRenderClip(reducedClip.elementsGenID(), reducedCl
ip.ibounds(), | |
608 clipSpaceToStencilOffset)) { | |
609 stencilAttachment->setLastClip(reducedClip.elementsGenID(), reducedClip.
ibounds(), | |
610 clipSpaceToStencilOffset); | |
611 // Set the matrix so that rendered clip elements are transformed from cl
ip to stencil space. | |
612 SkVector translate = { | |
613 SkIntToScalar(clipSpaceToStencilOffset.fX), | |
614 SkIntToScalar(clipSpaceToStencilOffset.fY) | |
615 }; | |
616 SkMatrix viewMatrix; | |
617 viewMatrix.setTranslate(translate); | |
618 | |
619 // We set the current clip to the bounds so that our recursive draws are
scissored to them. | |
620 SkIRect stencilSpaceIBounds(reducedClip.ibounds()); | |
621 stencilSpaceIBounds.offset(clipSpaceToStencilOffset); | |
622 StencilClip stencilClip(stencilSpaceIBounds); | |
623 | |
624 bool initialState = InitialState::kAllIn == reducedClip.initialState(); | |
625 drawContext->drawContextPriv().clearStencilClip(stencilClip.fixedClip(),
initialState); | |
626 | |
627 // walk through each clip element and perform its set op | |
628 // with the existing clip. | |
629 for (ElementList::Iter iter(reducedClip.elements()); iter.get(); iter.ne
xt()) { | |
630 const Element* element = iter.get(); | |
631 bool useHWAA = element->isAA() && drawContext->isStencilBufferMultis
ampled(); | |
632 | |
633 bool fillInverted = false; | |
634 | |
635 // This will be used to determine whether the clip shape can be rend
ered into the | |
636 // stencil with arbitrary stencil settings. | |
637 GrPathRenderer::StencilSupport stencilSupport; | |
638 | |
639 SkRegion::Op op = element->getOp(); | |
640 | |
641 GrPathRenderer* pr = nullptr; | |
642 SkPath clipPath; | |
643 if (Element::kRect_Type == element->getType()) { | |
644 stencilSupport = GrPathRenderer::kNoRestriction_StencilSupport; | |
645 fillInverted = false; | |
646 } else { | |
647 element->asPath(&clipPath); | |
648 fillInverted = clipPath.isInverseFillType(); | |
649 if (fillInverted) { | |
650 clipPath.toggleInverseFillType(); | |
651 } | |
652 | |
653 GrShape shape(clipPath, GrStyle::SimpleFill()); | |
654 GrPathRenderer::CanDrawPathArgs canDrawArgs; | |
655 canDrawArgs.fShaderCaps = context->caps()->shaderCaps(); | |
656 canDrawArgs.fViewMatrix = &viewMatrix; | |
657 canDrawArgs.fShape = &shape; | |
658 canDrawArgs.fAntiAlias = false; | |
659 canDrawArgs.fHasUserStencilSettings = false; | |
660 canDrawArgs.fIsStencilBufferMSAA = drawContext->isStencilBufferM
ultisampled(); | |
661 | |
662 GrDrawingManager* dm = context->drawingManager(); | |
663 pr = dm->getPathRenderer(canDrawArgs, false, | |
664 GrPathRendererChain::kStencilOnly_DrawT
ype, | |
665 &stencilSupport); | |
666 if (!pr) { | |
667 return false; | |
668 } | |
669 } | |
670 | |
671 bool canRenderDirectToStencil = | |
672 GrPathRenderer::kNoRestriction_StencilSupport == stencilSupport; | |
673 bool drawDirectToClip; // Given the renderer, the element, | |
674 // fill rule, and set operation should | |
675 // we render the element directly to | |
676 // stencil bit used for clipping. | |
677 GrUserStencilSettings const* const* stencilPasses = | |
678 GrStencilSettings::GetClipPasses(op, canRenderDirectToStencil, f
illInverted, | |
679 &drawDirectToClip); | |
680 | |
681 // draw the element to the client stencil bits if necessary | |
682 if (!drawDirectToClip) { | |
683 static constexpr GrUserStencilSettings kDrawToStencil( | |
684 GrUserStencilSettings::StaticInit< | |
685 0x0000, | |
686 GrUserStencilTest::kAlways, | |
687 0xffff, | |
688 GrUserStencilOp::kIncMaybeClamp, | |
689 GrUserStencilOp::kIncMaybeClamp, | |
690 0xffff>() | |
691 ); | |
692 if (Element::kRect_Type == element->getType()) { | |
693 drawContext->drawContextPriv().stencilRect(stencilClip.fixed
Clip(), | |
694 &kDrawToStencil,
useHWAA, | |
695 viewMatrix, eleme
nt->getRect()); | |
696 } else { | |
697 if (!clipPath.isEmpty()) { | |
698 GrShape shape(clipPath, GrStyle::SimpleFill()); | |
699 if (canRenderDirectToStencil) { | |
700 GrPaint paint; | |
701 paint.setXPFactory(GrDisableColorXPFactory::Make()); | |
702 paint.setAntiAlias(element->isAA()); | |
703 | |
704 GrPathRenderer::DrawPathArgs args; | |
705 args.fResourceProvider = context->resourceProvider()
; | |
706 args.fPaint = &paint; | |
707 args.fUserStencilSettings = &kDrawToStencil; | |
708 args.fDrawContext = drawContext; | |
709 args.fClip = &stencilClip.fixedClip(); | |
710 args.fViewMatrix = &viewMatrix; | |
711 args.fShape = &shape; | |
712 args.fAntiAlias = false; | |
713 args.fGammaCorrect = false; | |
714 pr->drawPath(args); | |
715 } else { | |
716 GrPathRenderer::StencilPathArgs args; | |
717 args.fResourceProvider = context->resourceProvider()
; | |
718 args.fDrawContext = drawContext; | |
719 args.fClip = &stencilClip.fixedClip(); | |
720 args.fViewMatrix = &viewMatrix; | |
721 args.fIsAA = element->isAA(); | |
722 args.fShape = &shape; | |
723 pr->stencilPath(args); | |
724 } | |
725 } | |
726 } | |
727 } | |
728 | |
729 // now we modify the clip bit by rendering either the clip | |
730 // element directly or a bounding rect of the entire clip. | |
731 for (GrUserStencilSettings const* const* pass = stencilPasses; *pass
; ++pass) { | |
732 if (drawDirectToClip) { | |
733 if (Element::kRect_Type == element->getType()) { | |
734 drawContext->drawContextPriv().stencilRect(stencilClip,
*pass, useHWAA, | |
735 viewMatrix, e
lement->getRect()); | |
736 } else { | |
737 GrShape shape(clipPath, GrStyle::SimpleFill()); | |
738 GrPaint paint; | |
739 paint.setXPFactory(GrDisableColorXPFactory::Make()); | |
740 paint.setAntiAlias(element->isAA()); | |
741 GrPathRenderer::DrawPathArgs args; | |
742 args.fResourceProvider = context->resourceProvider(); | |
743 args.fPaint = &paint; | |
744 args.fUserStencilSettings = *pass; | |
745 args.fDrawContext = drawContext; | |
746 args.fClip = &stencilClip; | |
747 args.fViewMatrix = &viewMatrix; | |
748 args.fShape = &shape; | |
749 args.fAntiAlias = false; | |
750 args.fGammaCorrect = false; | |
751 pr->drawPath(args); | |
752 } | |
753 } else { | |
754 // The view matrix is setup to do clip space -> stencil spac
e translation, so | |
755 // draw rect in clip space. | |
756 drawContext->drawContextPriv().stencilRect(stencilClip, *pas
s, | |
757 false, viewMatrix
, | |
758 SkRect::Make(redu
cedClip.ibounds())); | |
759 } | |
760 } | |
761 } | |
762 } | |
763 return true; | |
764 } | |
765 | |
766 //////////////////////////////////////////////////////////////////////////////// | |
767 sk_sp<GrTexture> GrClipStackClip::CreateSoftwareClipMask(GrTextureProvider* texP
rovider, | 440 sk_sp<GrTexture> GrClipStackClip::CreateSoftwareClipMask(GrTextureProvider* texP
rovider, |
768 const GrReducedClip& re
ducedClip, | 441 const GrReducedClip& re
ducedClip) { |
769 const SkVector& clipToM
askOffset) { | |
770 GrUniqueKey key; | 442 GrUniqueKey key; |
771 GetClipMaskKey(reducedClip.elementsGenID(), reducedClip.ibounds(), &key); | 443 GetClipMaskKey(reducedClip.elementsGenID(), reducedClip.ibounds(), &key); |
772 if (GrTexture* texture = texProvider->findAndRefTextureByUniqueKey(key)) { | 444 if (GrTexture* texture = texProvider->findAndRefTextureByUniqueKey(key)) { |
773 return sk_sp<GrTexture>(texture); | 445 return sk_sp<GrTexture>(texture); |
774 } | 446 } |
775 | 447 |
776 // The mask texture may be larger than necessary. We round out the clip spac
e bounds and pin | 448 // The mask texture may be larger than necessary. We round out the clip spac
e bounds and pin |
777 // the top left corner of the resulting rect to the top left of the texture. | 449 // the top left corner of the resulting rect to the top left of the texture. |
778 SkIRect maskSpaceIBounds = SkIRect::MakeWH(reducedClip.width(), reducedClip.
height()); | 450 SkIRect maskSpaceIBounds = SkIRect::MakeWH(reducedClip.width(), reducedClip.
height()); |
779 | 451 |
780 GrSWMaskHelper helper(texProvider); | 452 GrSWMaskHelper helper(texProvider); |
781 | 453 |
782 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip | 454 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip |
783 // space. | 455 // space. |
784 SkMatrix translate; | 456 SkMatrix translate; |
785 translate.setTranslate(clipToMaskOffset); | 457 translate.setTranslate(SkIntToScalar(-reducedClip.left()), SkIntToScalar(-re
ducedClip.top())); |
786 | 458 |
787 helper.init(maskSpaceIBounds, &translate); | 459 helper.init(maskSpaceIBounds, &translate); |
788 helper.clear(InitialState::kAllIn == reducedClip.initialState() ? 0xFF : 0x0
0); | 460 helper.clear(InitialState::kAllIn == reducedClip.initialState() ? 0xFF : 0x0
0); |
789 | 461 |
790 for (ElementList::Iter iter(reducedClip.elements()); iter.get(); iter.next()
) { | 462 for (ElementList::Iter iter(reducedClip.elements()); iter.get(); iter.next()
) { |
791 const Element* element = iter.get(); | 463 const Element* element = iter.get(); |
792 SkRegion::Op op = element->getOp(); | 464 SkRegion::Op op = element->getOp(); |
793 | 465 |
794 if (SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op ==
op) { | 466 if (SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op ==
op) { |
795 // Intersect and reverse difference require modifying pixels outside
of the geometry | 467 // Intersect and reverse difference require modifying pixels outside
of the geometry |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
830 sk_sp<GrTexture> result(texProvider->createApproxTexture(desc)); | 502 sk_sp<GrTexture> result(texProvider->createApproxTexture(desc)); |
831 if (!result) { | 503 if (!result) { |
832 return nullptr; | 504 return nullptr; |
833 } | 505 } |
834 result->resourcePriv().setUniqueKey(key); | 506 result->resourcePriv().setUniqueKey(key); |
835 | 507 |
836 helper.toTexture(result.get()); | 508 helper.toTexture(result.get()); |
837 | 509 |
838 return result; | 510 return result; |
839 } | 511 } |
OLD | NEW |