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" |
11 #include "GrDrawContextPriv.h" | 11 #include "GrDrawContext.h" |
12 #include "GrDrawTarget.h" | 12 #include "GrDrawTarget.h" |
13 #include "GrGpuResourcePriv.h" | 13 #include "GrGpuResourcePriv.h" |
14 #include "GrPaint.h" | 14 #include "GrPaint.h" |
15 #include "GrPathRenderer.h" | 15 #include "GrPathRenderer.h" |
16 #include "GrRenderTarget.h" | 16 #include "GrRenderTarget.h" |
17 #include "GrRenderTargetPriv.h" | 17 #include "GrRenderTargetPriv.h" |
18 #include "GrResourceProvider.h" | 18 #include "GrResourceProvider.h" |
19 #include "GrStencilAttachment.h" | 19 #include "GrStencilAttachment.h" |
20 #include "GrSWMaskHelper.h" | 20 #include "GrSWMaskHelper.h" |
21 #include "SkRasterClip.h" | 21 #include "SkRasterClip.h" |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
152 } | 152 } |
153 | 153 |
154 GrResourceProvider* GrClipMaskManager::resourceProvider() { | 154 GrResourceProvider* GrClipMaskManager::resourceProvider() { |
155 return fDrawTarget->cmmAccess().resourceProvider(); | 155 return fDrawTarget->cmmAccess().resourceProvider(); |
156 } | 156 } |
157 /* | 157 /* |
158 * This method traverses the clip stack to see if the GrSoftwarePathRenderer | 158 * This method traverses the clip stack to see if the GrSoftwarePathRenderer |
159 * will be used on any element. If so, it returns true to indicate that the | 159 * will be used on any element. If so, it returns true to indicate that the |
160 * entire clip should be rendered in SW and then uploaded en masse to the gpu. | 160 * entire clip should be rendered in SW and then uploaded en masse to the gpu. |
161 */ | 161 */ |
162 bool GrClipMaskManager::UseSWOnlyPath(GrContext* context, | 162 bool GrClipMaskManager::useSWOnlyPath(const GrPipelineBuilder& pipelineBuilder, |
163 const GrPipelineBuilder& pipelineBuilder, | |
164 const GrRenderTarget* rt, | 163 const GrRenderTarget* rt, |
165 const SkVector& clipToMaskOffset, | 164 const SkVector& clipToMaskOffset, |
166 const GrReducedClip::ElementList& elements
) { | 165 const GrReducedClip::ElementList& elements
) { |
167 // TODO: generalize this function so that when | 166 // TODO: generalize this function so that when |
168 // a clip gets complex enough it can just be done in SW regardless | 167 // a clip gets complex enough it can just be done in SW regardless |
169 // of whether it would invoke the GrSoftwarePathRenderer. | 168 // of whether it would invoke the GrSoftwarePathRenderer. |
170 | 169 |
171 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip | 170 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip |
172 // space. | 171 // space. |
173 const SkMatrix translate = SkMatrix::MakeTrans(clipToMaskOffset.fX, clipToMa
skOffset.fY); | 172 const SkMatrix translate = SkMatrix::MakeTrans(clipToMaskOffset.fX, clipToMa
skOffset.fY); |
174 | 173 |
175 for (GrReducedClip::ElementList::Iter iter(elements.headIter()); iter.get();
iter.next()) { | 174 for (GrReducedClip::ElementList::Iter iter(elements.headIter()); iter.get();
iter.next()) { |
176 const Element* element = iter.get(); | 175 const Element* element = iter.get(); |
177 | 176 |
178 SkRegion::Op op = element->getOp(); | 177 SkRegion::Op op = element->getOp(); |
179 bool invert = element->isInverseFilled(); | 178 bool invert = element->isInverseFilled(); |
180 bool needsStencil = invert || | 179 bool needsStencil = invert || |
181 SkRegion::kIntersect_Op == op || SkRegion::kReverseD
ifference_Op == op; | 180 SkRegion::kIntersect_Op == op || SkRegion::kReverseD
ifference_Op == op; |
182 | 181 |
183 if (PathNeedsSWRenderer(context, pipelineBuilder.getStencil().isDisabled
(), | 182 if (PathNeedsSWRenderer(this->getContext(), pipelineBuilder.getStencil()
.isDisabled(), |
184 rt, translate, element, nullptr, needsStencil))
{ | 183 rt, translate, element, nullptr, needsStencil))
{ |
185 return true; | 184 return true; |
186 } | 185 } |
187 } | 186 } |
188 return false; | 187 return false; |
189 } | 188 } |
190 | 189 |
191 bool GrClipMaskManager::getAnalyticClipProcessor(const GrReducedClip::ElementLis
t& elements, | 190 bool GrClipMaskManager::getAnalyticClipProcessor(const GrReducedClip::ElementLis
t& elements, |
192 bool abortIfAA, | 191 bool abortIfAA, |
193 SkVector& clipToRTOffset, | 192 SkVector& clipToRTOffset, |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
310 if (intersect.intersect(clip.irect())) { | 309 if (intersect.intersect(clip.irect())) { |
311 *out = GrClip(intersect); | 310 *out = GrClip(intersect); |
312 } else { | 311 } else { |
313 *out = clip; | 312 *out = clip; |
314 } | 313 } |
315 break; | 314 break; |
316 } | 315 } |
317 } | 316 } |
318 } | 317 } |
319 | 318 |
320 bool GrClipMaskManager::setupScissorClip(const GrPipelineBuilder& pipelineBuilde
r, | |
321 GrPipelineBuilder::AutoRestoreStencil*
ars, | |
322 const SkIRect& clipScissor, | |
323 const SkRect* devBounds, | |
324 GrAppliedClip* out) { | |
325 if (kRespectClip_StencilClipMode == fClipMode) { | |
326 fClipMode = kIgnoreClip_StencilClipMode; | |
327 } | |
328 | |
329 GrRenderTarget* rt = pipelineBuilder.getRenderTarget(); | |
330 | |
331 SkIRect clipSpaceRTIBounds = SkIRect::MakeWH(rt->width(), rt->height()); | |
332 SkIRect devBoundsScissor; | |
333 const SkIRect* scissor = &clipScissor; | |
334 bool doDevBoundsClip = fDebugClipBatchToBounds && devBounds; | |
335 if (doDevBoundsClip) { | |
336 devBounds->roundOut(&devBoundsScissor); | |
337 if (devBoundsScissor.intersect(clipScissor)) { | |
338 scissor = &devBoundsScissor; | |
339 } | |
340 } | |
341 | |
342 if (scissor->contains(clipSpaceRTIBounds)) { | |
343 // This counts as wide open | |
344 this->setPipelineBuilderStencil(pipelineBuilder, ars); | |
345 return true; | |
346 } | |
347 | |
348 if (clipSpaceRTIBounds.intersect(*scissor)) { | |
349 out->fScissorState.set(clipSpaceRTIBounds); | |
350 this->setPipelineBuilderStencil(pipelineBuilder, ars); | |
351 return true; | |
352 } | |
353 return false; | |
354 } | |
355 | |
356 //////////////////////////////////////////////////////////////////////////////// | 319 //////////////////////////////////////////////////////////////////////////////// |
357 // sort out what kind of clip mask needs to be created: alpha, stencil, | 320 // sort out what kind of clip mask needs to be created: alpha, stencil, |
358 // scissor, or entirely software | 321 // scissor, or entirely software |
359 bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder, | 322 bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder, |
360 GrPipelineBuilder::AutoRestoreStencil* ars
, | 323 GrPipelineBuilder::AutoRestoreStencil* ars
, |
361 const SkRect* devBounds, | 324 const SkRect* devBounds, |
362 GrAppliedClip* out) { | 325 GrAppliedClip* out) { |
363 if (kRespectClip_StencilClipMode == fClipMode) { | 326 if (kRespectClip_StencilClipMode == fClipMode) { |
364 fClipMode = kIgnoreClip_StencilClipMode; | 327 fClipMode = kIgnoreClip_StencilClipMode; |
365 } | 328 } |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
469 // If the stencil buffer is multisampled we can use it to do everything. | 432 // If the stencil buffer is multisampled we can use it to do everything. |
470 if (!rt->isStencilBufferMultisampled() && requiresAA) { | 433 if (!rt->isStencilBufferMultisampled() && requiresAA) { |
471 SkAutoTUnref<GrTexture> result; | 434 SkAutoTUnref<GrTexture> result; |
472 | 435 |
473 // The top-left of the mask corresponds to the top-left corner of the bo
unds. | 436 // The top-left of the mask corresponds to the top-left corner of the bo
unds. |
474 SkVector clipToMaskOffset = { | 437 SkVector clipToMaskOffset = { |
475 SkIntToScalar(-clipSpaceIBounds.fLeft), | 438 SkIntToScalar(-clipSpaceIBounds.fLeft), |
476 SkIntToScalar(-clipSpaceIBounds.fTop) | 439 SkIntToScalar(-clipSpaceIBounds.fTop) |
477 }; | 440 }; |
478 | 441 |
479 if (UseSWOnlyPath(this->getContext(), pipelineBuilder, rt, clipToMaskOff
set, elements)) { | 442 if (this->useSWOnlyPath(pipelineBuilder, rt, clipToMaskOffset, elements)
) { |
480 // The clip geometry is complex enough that it will be more efficien
t to create it | 443 // The clip geometry is complex enough that it will be more efficien
t to create it |
481 // entirely in software | 444 // entirely in software |
482 result.reset(CreateSoftwareClipMask(this->getContext(), | 445 result.reset(this->createSoftwareClipMask(genID, |
483 genID, | 446 initialState, |
484 initialState, | 447 elements, |
485 elements, | 448 clipToMaskOffset, |
486 clipToMaskOffset, | 449 clipSpaceIBounds)); |
487 clipSpaceIBounds)); | |
488 } else { | 450 } else { |
489 result.reset(CreateAlphaClipMask(this->getContext(), | 451 result.reset(this->createAlphaClipMask(genID, |
490 genID, | 452 initialState, |
491 initialState, | 453 elements, |
492 elements, | 454 clipToMaskOffset, |
493 clipToMaskOffset, | 455 clipSpaceIBounds)); |
494 clipSpaceIBounds)); | 456 // If createAlphaClipMask fails it means useSWOnlyPath has a bug |
495 // If createAlphaClipMask fails it means UseSWOnlyPath has a bug | |
496 SkASSERT(result); | 457 SkASSERT(result); |
497 } | 458 } |
498 | 459 |
499 if (result) { | 460 if (result) { |
500 // The mask's top left coord should be pinned to the rounded-out top
left corner of | 461 // The mask's top left coord should be pinned to the rounded-out top
left corner of |
501 // clipSpace bounds. We determine the mask's position WRT to the ren
der target here. | 462 // clipSpace bounds. We determine the mask's position WRT to the ren
der target here. |
502 SkIRect rtSpaceMaskBounds = clipSpaceIBounds; | 463 SkIRect rtSpaceMaskBounds = clipSpaceIBounds; |
503 rtSpaceMaskBounds.offset(-clip.origin()); | 464 rtSpaceMaskBounds.offset(-clip.origin()); |
504 out->fClipCoverageFP.reset(create_fp_for_mask(result, rtSpaceMaskBou
nds)); | 465 out->fClipCoverageFP.reset(create_fp_for_mask(result, rtSpaceMaskBou
nds)); |
505 this->setPipelineBuilderStencil(pipelineBuilder, ars); | 466 this->setPipelineBuilderStencil(pipelineBuilder, ars); |
(...skipping 14 matching lines...) Expand all Loading... |
520 // This must occur after createStencilClipMask. That function may change the
scissor. Also, it | 481 // This must occur after createStencilClipMask. That function may change the
scissor. Also, it |
521 // only guarantees that the stencil mask is correct within the bounds it was
passed, so we must | 482 // only guarantees that the stencil mask is correct within the bounds it was
passed, so we must |
522 // use both stencil and scissor test to the bounds for the final draw. | 483 // use both stencil and scissor test to the bounds for the final draw. |
523 SkIRect scissorSpaceIBounds(clipSpaceIBounds); | 484 SkIRect scissorSpaceIBounds(clipSpaceIBounds); |
524 scissorSpaceIBounds.offset(clipSpaceToStencilSpaceOffset); | 485 scissorSpaceIBounds.offset(clipSpaceToStencilSpaceOffset); |
525 out->fScissorState.set(scissorSpaceIBounds); | 486 out->fScissorState.set(scissorSpaceIBounds); |
526 this->setPipelineBuilderStencil(pipelineBuilder, ars); | 487 this->setPipelineBuilderStencil(pipelineBuilder, ars); |
527 return true; | 488 return true; |
528 } | 489 } |
529 | 490 |
530 static bool stencil_element(GrDrawContext* dc, | 491 namespace { |
531 const SkIRect* scissorRect, | 492 //////////////////////////////////////////////////////////////////////////////// |
532 const GrStencilSettings& ss, | 493 // Set a coverage drawing XPF on the pipelineBuilder for the given op and invert
Coverage mode |
533 const SkMatrix& viewMatrix, | 494 void set_coverage_drawing_xpf(SkRegion::Op op, bool invertCoverage, |
534 const SkClipStack::Element* element) { | 495 GrPipelineBuilder* pipelineBuilder) { |
| 496 SkASSERT(op <= SkRegion::kLastOp); |
| 497 pipelineBuilder->setCoverageSetOpXPFactory(op, invertCoverage); |
| 498 } |
| 499 } |
| 500 |
| 501 //////////////////////////////////////////////////////////////////////////////// |
| 502 bool GrClipMaskManager::drawElement(GrPipelineBuilder* pipelineBuilder, |
| 503 const SkMatrix& viewMatrix, |
| 504 GrTexture* target, |
| 505 const SkClipStack::Element* element, |
| 506 GrPathRenderer* pr) { |
| 507 |
| 508 GrRenderTarget* rt = target->asRenderTarget(); |
| 509 pipelineBuilder->setRenderTarget(rt); |
| 510 |
| 511 // The color we use to draw does not matter since we will always be using a
GrCoverageSetOpXP |
| 512 // which ignores color. |
| 513 GrColor color = GrColor_WHITE; |
535 | 514 |
536 // TODO: Draw rrects directly here. | 515 // TODO: Draw rrects directly here. |
537 switch (element->getType()) { | 516 switch (element->getType()) { |
538 case Element::kEmpty_Type: | 517 case Element::kEmpty_Type: |
539 SkDEBUGFAIL("Should never get here with an empty element."); | 518 SkDEBUGFAIL("Should never get here with an empty element."); |
540 break; | 519 break; |
541 case Element::kRect_Type: | 520 case Element::kRect_Type: { |
542 return dc->drawContextPriv().drawAndStencilRect(scissorRect, ss, | 521 // TODO: Do rects directly to the accumulator using a aa-rect GrProc
essor that covers |
543 element->getOp(), | 522 // the entire mask bounds and writes 0 outside the rect. |
544 element->isInverseFi
lled(), | 523 if (element->isAA()) { |
545 element->isAA(), | 524 SkRect devRect = element->getRect(); |
546 viewMatrix, element-
>getRect()); | 525 viewMatrix.mapRect(&devRect); |
547 break; | 526 |
| 527 SkAutoTUnref<GrDrawBatch> batch( |
| 528 GrRectBatchFactory::CreateAAFill(color, viewMatrix, elem
ent->getRect(), |
| 529 devRect)); |
| 530 |
| 531 fDrawTarget->drawBatch(*pipelineBuilder, batch); |
| 532 } else { |
| 533 draw_non_aa_rect(fDrawTarget, *pipelineBuilder, color, viewMatri
x, |
| 534 element->getRect()); |
| 535 } |
| 536 return true; |
| 537 } |
548 default: { | 538 default: { |
549 SkPath path; | 539 SkPath path; |
550 element->asPath(&path); | 540 element->asPath(&path); |
551 if (path.isInverseFillType()) { | 541 if (path.isInverseFillType()) { |
552 path.toggleInverseFillType(); | 542 path.toggleInverseFillType(); |
553 } | 543 } |
| 544 GrStrokeInfo stroke(SkStrokeRec::kFill_InitStyle); |
| 545 if (nullptr == pr) { |
| 546 GrPathRendererChain::DrawType type; |
| 547 type = element->isAA() ? GrPathRendererChain::kColorAntiAlias_Dr
awType : |
| 548 GrPathRendererChain::kColor_DrawType; |
554 | 549 |
555 return dc->drawContextPriv().drawAndStencilPath(scissorRect, ss, | 550 GrPathRenderer::CanDrawPathArgs canDrawArgs; |
556 element->getOp(), | 551 canDrawArgs.fShaderCaps = this->getContext()->caps()->shaderCaps
(); |
557 element->isInverseFi
lled(), | 552 canDrawArgs.fViewMatrix = &viewMatrix; |
558 element->isAA(), vie
wMatrix, path); | 553 canDrawArgs.fPath = &path; |
| 554 canDrawArgs.fStroke = &stroke; |
| 555 canDrawArgs.fAntiAlias = element->isAA();; |
| 556 canDrawArgs.fIsStencilDisabled = pipelineBuilder->getStencil().i
sDisabled(); |
| 557 canDrawArgs.fIsStencilBufferMSAA = rt->isStencilBufferMultisampl
ed(); |
| 558 |
| 559 pr = this->getContext()->drawingManager()->getPathRenderer(canDr
awArgs, false, type); |
| 560 } |
| 561 if (nullptr == pr) { |
| 562 return false; |
| 563 } |
| 564 GrPathRenderer::DrawPathArgs args; |
| 565 args.fTarget = fDrawTarget; |
| 566 args.fResourceProvider = this->getContext()->resourceProvider(); |
| 567 args.fPipelineBuilder = pipelineBuilder; |
| 568 args.fColor = color; |
| 569 args.fViewMatrix = &viewMatrix; |
| 570 args.fPath = &path; |
| 571 args.fStroke = &stroke; |
| 572 args.fAntiAlias = element->isAA(); |
| 573 pr->drawPath(args); |
559 break; | 574 break; |
560 } | 575 } |
561 } | 576 } |
562 | 577 return true; |
563 return false; | |
564 } | |
565 | |
566 static void draw_element(GrDrawContext* dc, | |
567 const GrClip& clip, // TODO: can this just always be Wi
deOpen? | |
568 const GrPaint &paint, | |
569 const SkMatrix& viewMatrix, | |
570 const SkClipStack::Element* element) { | |
571 | |
572 // TODO: Draw rrects directly here. | |
573 switch (element->getType()) { | |
574 case Element::kEmpty_Type: | |
575 SkDEBUGFAIL("Should never get here with an empty element."); | |
576 break; | |
577 case Element::kRect_Type: | |
578 dc->drawRect(clip, paint, viewMatrix, element->getRect()); | |
579 break; | |
580 default: { | |
581 SkPath path; | |
582 element->asPath(&path); | |
583 if (path.isInverseFillType()) { | |
584 path.toggleInverseFillType(); | |
585 } | |
586 | |
587 dc->drawPath(clip, paint, viewMatrix, path, GrStrokeInfo::FillInfo()
); | |
588 break; | |
589 } | |
590 } | |
591 } | 578 } |
592 | 579 |
593 //////////////////////////////////////////////////////////////////////////////// | 580 //////////////////////////////////////////////////////////////////////////////// |
594 // Create a 8-bit clip mask in alpha | 581 // Create a 8-bit clip mask in alpha |
595 | 582 |
596 static void GetClipMaskKey(int32_t clipGenID, const SkIRect& bounds, GrUniqueKey
* key) { | 583 static void GetClipMaskKey(int32_t clipGenID, const SkIRect& bounds, GrUniqueKey
* key) { |
597 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); | 584 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); |
598 GrUniqueKey::Builder builder(key, kDomain, 3); | 585 GrUniqueKey::Builder builder(key, kDomain, 3); |
599 builder[0] = clipGenID; | 586 builder[0] = clipGenID; |
600 builder[1] = SkToU16(bounds.fLeft) | (SkToU16(bounds.fRight) << 16); | 587 builder[1] = SkToU16(bounds.fLeft) | (SkToU16(bounds.fRight) << 16); |
601 builder[2] = SkToU16(bounds.fTop) | (SkToU16(bounds.fBottom) << 16); | 588 builder[2] = SkToU16(bounds.fTop) | (SkToU16(bounds.fBottom) << 16); |
602 } | 589 } |
603 | 590 |
604 GrTexture* GrClipMaskManager::CreateAlphaClipMask(GrContext* context, | 591 GrTexture* GrClipMaskManager::createCachedMask(int width, int height, const GrUn
iqueKey& key, |
605 int32_t elementsGenID, | 592 bool renderTarget) { |
| 593 GrSurfaceDesc desc; |
| 594 desc.fWidth = width; |
| 595 desc.fHeight = height; |
| 596 desc.fFlags = renderTarget ? kRenderTarget_GrSurfaceFlag : kNone_GrSurfaceFl
ags; |
| 597 if (!renderTarget || this->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig
, false)) { |
| 598 desc.fConfig = kAlpha_8_GrPixelConfig; |
| 599 } else { |
| 600 desc.fConfig = kRGBA_8888_GrPixelConfig; |
| 601 } |
| 602 |
| 603 GrTexture* texture = this->resourceProvider()->createApproxTexture(desc, 0); |
| 604 if (!texture) { |
| 605 return nullptr; |
| 606 } |
| 607 texture->resourcePriv().setUniqueKey(key); |
| 608 return texture; |
| 609 } |
| 610 |
| 611 GrTexture* GrClipMaskManager::createAlphaClipMask(int32_t elementsGenID, |
606 GrReducedClip::InitialState in
itialState, | 612 GrReducedClip::InitialState in
itialState, |
607 const GrReducedClip::ElementLi
st& elements, | 613 const GrReducedClip::ElementLi
st& elements, |
608 const SkVector& clipToMaskOffs
et, | 614 const SkVector& clipToMaskOffs
et, |
609 const SkIRect& clipSpaceIBound
s) { | 615 const SkIRect& clipSpaceIBound
s) { |
610 GrResourceProvider* resourceProvider = context->resourceProvider(); | 616 GrResourceProvider* resourceProvider = this->resourceProvider(); |
611 GrUniqueKey key; | 617 GrUniqueKey key; |
612 GetClipMaskKey(elementsGenID, clipSpaceIBounds, &key); | 618 GetClipMaskKey(elementsGenID, clipSpaceIBounds, &key); |
613 if (GrTexture* texture = resourceProvider->findAndRefTextureByUniqueKey(key)
) { | 619 if (GrTexture* texture = resourceProvider->findAndRefTextureByUniqueKey(key)
) { |
614 return texture; | 620 return texture; |
615 } | 621 } |
616 | 622 |
617 // There's no texture in the cache. Let's try to allocate it then. | 623 // There's no texture in the cache. Let's try to allocate it then. |
618 GrSurfaceDesc desc; | 624 SkAutoTUnref<GrTexture> texture(this->createCachedMask( |
619 desc.fWidth = clipSpaceIBounds.width(); | 625 clipSpaceIBounds.width(), clipSpaceIBounds.height(), key, true)); |
620 desc.fHeight = clipSpaceIBounds.height(); | |
621 desc.fFlags = kRenderTarget_GrSurfaceFlag; | |
622 if (context->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) { | |
623 desc.fConfig = kAlpha_8_GrPixelConfig; | |
624 } else { | |
625 desc.fConfig = kRGBA_8888_GrPixelConfig; | |
626 } | |
627 | |
628 SkAutoTUnref<GrTexture> texture(resourceProvider->createApproxTexture(desc,
0)); | |
629 if (!texture) { | 626 if (!texture) { |
630 return nullptr; | 627 return nullptr; |
631 } | 628 } |
632 | 629 |
633 texture->resourcePriv().setUniqueKey(key); | 630 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip |
634 | 631 // space. |
635 SkAutoTUnref<GrDrawContext> dc(context->drawContext(texture->asRenderTarget(
))); | 632 const SkMatrix translate = SkMatrix::MakeTrans(clipToMaskOffset.fX, clipToMa
skOffset.fY); |
636 if (!dc) { | |
637 return nullptr; | |
638 } | |
639 | 633 |
640 // The texture may be larger than necessary, this rect represents the part o
f the texture | 634 // The texture may be larger than necessary, this rect represents the part o
f the texture |
641 // we populate with a rasterization of the clip. | 635 // we populate with a rasterization of the clip. |
642 SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpa
ceIBounds.height()); | 636 SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpa
ceIBounds.height()); |
643 | 637 |
644 // The scratch texture that we are drawing into can be substantially larger
than the mask. Only | 638 // The scratch texture that we are drawing into can be substantially larger
than the mask. Only |
645 // clear the part that we care about. | 639 // clear the part that we care about. |
646 dc->clear(&maskSpaceIBounds, | 640 fDrawTarget->clear(&maskSpaceIBounds, |
647 GrReducedClip::kAllIn_InitialState == initialState ? 0xffffffff :
0x00000000, | 641 GrReducedClip::kAllIn_InitialState == initialState ? 0xff
ffffff : 0x00000000, |
648 true); | 642 true, |
| 643 texture->asRenderTarget()); |
649 | 644 |
650 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip | 645 // When we use the stencil in the below loop it is important to have this cl
ip installed. |
651 // space. | |
652 const SkMatrix translate = SkMatrix::MakeTrans(clipToMaskOffset.fX, clipToMa
skOffset.fY); | |
653 | |
654 // It is important that we use maskSpaceIBounds as the stencil rect in the b
elow loop. | |
655 // The second pass that zeros the stencil buffer renders the rect maskSpaceI
Bounds so the first | 646 // The second pass that zeros the stencil buffer renders the rect maskSpaceI
Bounds so the first |
656 // pass must not set values outside of this bounds or stencil values outside
the rect won't be | 647 // pass must not set values outside of this bounds or stencil values outside
the rect won't be |
657 // cleared. | 648 // cleared. |
| 649 const GrClip clip(maskSpaceIBounds); |
658 | 650 |
659 // walk through each clip element and perform its set op | 651 // walk through each clip element and perform its set op |
660 for (GrReducedClip::ElementList::Iter iter = elements.headIter(); iter.get()
; iter.next()) { | 652 for (GrReducedClip::ElementList::Iter iter = elements.headIter(); iter.get()
; iter.next()) { |
661 const Element* element = iter.get(); | 653 const Element* element = iter.get(); |
662 SkRegion::Op op = element->getOp(); | 654 SkRegion::Op op = element->getOp(); |
663 bool invert = element->isInverseFilled(); | 655 bool invert = element->isInverseFilled(); |
664 if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDiffere
nce_Op == op) { | 656 if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDiffere
nce_Op == op) { |
665 #ifdef SK_DEBUG | 657 |
666 GrPathRenderer* pr = GetPathRenderer(context, | 658 GrPathRenderer* pr = GetPathRenderer(this->getContext(), |
667 texture, translate, element); | 659 texture, translate, element); |
668 if (Element::kRect_Type != element->getType() && !pr) { | 660 if (Element::kRect_Type != element->getType() && !pr) { |
669 // UseSWOnlyPath should now filter out all cases where gpu-side
mask merging would | 661 // useSWOnlyPath should now filter out all cases where gpu-side
mask merging would |
670 // be performed (i.e., pr would be NULL for a non-rect path). | 662 // be performed (i.e., pr would be NULL for a non-rect path). Se
e https://bug.skia.org/4519 |
671 // See https://bug.skia.org/4519 for rationale and details. | 663 // for rationale and details. |
672 SkASSERT(0); | 664 SkASSERT(0); |
673 } | 665 continue; |
674 #endif | |
675 | |
676 // draw directly into the result with the stencil set to make the pi
xels affected | |
677 // by the clip shape be non-zero. | |
678 GR_STATIC_CONST_SAME_STENCIL(kStencilInElement, | |
679 kReplace_StencilOp, | |
680 kReplace_StencilOp, | |
681 kAlways_StencilFunc, | |
682 0xffff, | |
683 0xffff, | |
684 0xffff) | |
685 if (!stencil_element(dc, &maskSpaceIBounds, kStencilInElement, | |
686 translate, element)) { | |
687 texture->resourcePriv().removeUniqueKey(); | |
688 return nullptr; | |
689 } | 666 } |
690 | 667 |
691 // Draw to the exterior pixels (those with a zero stencil value). | 668 { |
692 GR_STATIC_CONST_SAME_STENCIL(kDrawOutsideElement, | 669 GrPipelineBuilder pipelineBuilder; |
693 kZero_StencilOp, | 670 |
694 kZero_StencilOp, | 671 pipelineBuilder.setClip(clip); |
695 kEqual_StencilFunc, | 672 pipelineBuilder.setRenderTarget(texture->asRenderTarget()); |
696 0xffff, | 673 SkASSERT(pipelineBuilder.getStencil().isDisabled()); |
697 0x0000, | 674 |
698 0xffff); | 675 // draw directly into the result with the stencil set to make th
e pixels affected |
699 if (!dc->drawContextPriv().drawAndStencilRect(&maskSpaceIBounds, kDr
awOutsideElement, | 676 // by the clip shape be non-zero. |
700 op, !invert, false, | 677 GR_STATIC_CONST_SAME_STENCIL(kStencilInElement, |
701 translate, | 678 kReplace_StencilOp, |
702 SkRect::Make(clipSpace
IBounds))) { | 679 kReplace_StencilOp, |
703 texture->resourcePriv().removeUniqueKey(); | 680 kAlways_StencilFunc, |
704 return nullptr; | 681 0xffff, |
| 682 0xffff, |
| 683 0xffff); |
| 684 pipelineBuilder.setStencil(kStencilInElement); |
| 685 set_coverage_drawing_xpf(op, invert, &pipelineBuilder); |
| 686 |
| 687 if (!this->drawElement(&pipelineBuilder, translate, texture, ele
ment, pr)) { |
| 688 texture->resourcePriv().removeUniqueKey(); |
| 689 return nullptr; |
| 690 } |
| 691 } |
| 692 |
| 693 { |
| 694 GrPipelineBuilder backgroundPipelineBuilder; |
| 695 backgroundPipelineBuilder.setRenderTarget(texture->asRenderTarge
t()); |
| 696 |
| 697 set_coverage_drawing_xpf(op, !invert, &backgroundPipelineBuilder
); |
| 698 // Draw to the exterior pixels (those with a zero stencil value)
. |
| 699 GR_STATIC_CONST_SAME_STENCIL(kDrawOutsideElement, |
| 700 kZero_StencilOp, |
| 701 kZero_StencilOp, |
| 702 kEqual_StencilFunc, |
| 703 0xffff, |
| 704 0x0000, |
| 705 0xffff); |
| 706 backgroundPipelineBuilder.setStencil(kDrawOutsideElement); |
| 707 |
| 708 // The color passed in here does not matter since the coverageSe
tOpXP won't read it. |
| 709 draw_non_aa_rect(fDrawTarget, backgroundPipelineBuilder, GrColor
_WHITE, translate, |
| 710 SkRect::Make(clipSpaceIBounds)); |
705 } | 711 } |
706 } else { | 712 } else { |
| 713 GrPipelineBuilder pipelineBuilder; |
| 714 |
707 // all the remaining ops can just be directly draw into the accumula
tion buffer | 715 // all the remaining ops can just be directly draw into the accumula
tion buffer |
708 GrPaint paint; | 716 set_coverage_drawing_xpf(op, false, &pipelineBuilder); |
709 paint.setAntiAlias(element->isAA()); | 717 // The color passed in here does not matter since the coverageSetOpX
P won't read it. |
710 paint.setCoverageSetOpXPFactory(op, false); | 718 this->drawElement(&pipelineBuilder, translate, texture, element); |
711 | |
712 draw_element(dc, GrClip::WideOpen(), paint, translate, element); | |
713 } | 719 } |
714 } | 720 } |
715 | 721 |
716 return texture.detach(); | 722 return texture.detach(); |
717 } | 723 } |
718 | 724 |
719 //////////////////////////////////////////////////////////////////////////////// | 725 //////////////////////////////////////////////////////////////////////////////// |
720 // Create a 1-bit clip mask in the stencil buffer. 'devClipBounds' are in device | 726 // Create a 1-bit clip mask in the stencil buffer. 'devClipBounds' are in device |
721 // (as opposed to canvas) coordinates | 727 // (as opposed to canvas) coordinates |
722 bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt, | 728 bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt, |
(...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1068 } else { | 1074 } else { |
1069 finished = true; | 1075 finished = true; |
1070 } | 1076 } |
1071 } | 1077 } |
1072 if (!twoSided) { | 1078 if (!twoSided) { |
1073 settings->copyFrontSettingsToBack(); | 1079 settings->copyFrontSettingsToBack(); |
1074 } | 1080 } |
1075 } | 1081 } |
1076 | 1082 |
1077 //////////////////////////////////////////////////////////////////////////////// | 1083 //////////////////////////////////////////////////////////////////////////////// |
1078 GrTexture* GrClipMaskManager::CreateSoftwareClipMask(GrContext* context, | 1084 GrTexture* GrClipMaskManager::createSoftwareClipMask(int32_t elementsGenID, |
1079 int32_t elementsGenID, | |
1080 GrReducedClip::InitialState
initialState, | 1085 GrReducedClip::InitialState
initialState, |
1081 const GrReducedClip::Elemen
tList& elements, | 1086 const GrReducedClip::Elemen
tList& elements, |
1082 const SkVector& clipToMaskO
ffset, | 1087 const SkVector& clipToMaskO
ffset, |
1083 const SkIRect& clipSpaceIBo
unds) { | 1088 const SkIRect& clipSpaceIBo
unds) { |
1084 GrUniqueKey key; | 1089 GrUniqueKey key; |
1085 GetClipMaskKey(elementsGenID, clipSpaceIBounds, &key); | 1090 GetClipMaskKey(elementsGenID, clipSpaceIBounds, &key); |
1086 GrResourceProvider* resourceProvider = context->resourceProvider(); | 1091 GrResourceProvider* resourceProvider = this->resourceProvider(); |
1087 if (GrTexture* texture = resourceProvider->findAndRefTextureByUniqueKey(key)
) { | 1092 if (GrTexture* texture = resourceProvider->findAndRefTextureByUniqueKey(key)
) { |
1088 return texture; | 1093 return texture; |
1089 } | 1094 } |
1090 | 1095 |
1091 // The mask texture may be larger than necessary. We round out the clip spac
e bounds and pin | 1096 // The mask texture may be larger than necessary. We round out the clip spac
e bounds and pin |
1092 // the top left corner of the resulting rect to the top left of the texture. | 1097 // the top left corner of the resulting rect to the top left of the texture. |
1093 SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpa
ceIBounds.height()); | 1098 SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpa
ceIBounds.height()); |
1094 | 1099 |
1095 GrSWMaskHelper helper(context); | 1100 GrSWMaskHelper helper(this->getContext()); |
1096 | 1101 |
1097 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip | 1102 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip |
1098 // space. | 1103 // space. |
1099 SkMatrix translate; | 1104 SkMatrix translate; |
1100 translate.setTranslate(clipToMaskOffset); | 1105 translate.setTranslate(clipToMaskOffset); |
1101 | 1106 |
1102 helper.init(maskSpaceIBounds, &translate, false); | 1107 helper.init(maskSpaceIBounds, &translate, false); |
1103 helper.clear(GrReducedClip::kAllIn_InitialState == initialState ? 0xFF : 0x0
0); | 1108 helper.clear(GrReducedClip::kAllIn_InitialState == initialState ? 0xFF : 0x0
0); |
1104 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); | 1109 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); |
1105 | 1110 |
(...skipping 23 matching lines...) Expand all Loading... |
1129 if (Element::kRect_Type == element->getType()) { | 1134 if (Element::kRect_Type == element->getType()) { |
1130 helper.draw(element->getRect(), op, element->isAA(), 0xFF); | 1135 helper.draw(element->getRect(), op, element->isAA(), 0xFF); |
1131 } else { | 1136 } else { |
1132 SkPath path; | 1137 SkPath path; |
1133 element->asPath(&path); | 1138 element->asPath(&path); |
1134 helper.draw(path, stroke, op, element->isAA(), 0xFF); | 1139 helper.draw(path, stroke, op, element->isAA(), 0xFF); |
1135 } | 1140 } |
1136 } | 1141 } |
1137 | 1142 |
1138 // Allocate clip mask texture | 1143 // Allocate clip mask texture |
1139 GrSurfaceDesc desc; | 1144 GrTexture* result = this->createCachedMask(clipSpaceIBounds.width(), clipSpa
ceIBounds.height(), |
1140 desc.fWidth = clipSpaceIBounds.width(); | 1145 key, false); |
1141 desc.fHeight = clipSpaceIBounds.height(); | 1146 if (nullptr == result) { |
1142 desc.fConfig = kAlpha_8_GrPixelConfig; | |
1143 | |
1144 GrTexture* result = context->resourceProvider()->createApproxTexture(desc, 0
); | |
1145 if (!result) { | |
1146 return nullptr; | 1147 return nullptr; |
1147 } | 1148 } |
1148 result->resourcePriv().setUniqueKey(key); | |
1149 | |
1150 helper.toTexture(result); | 1149 helper.toTexture(result); |
1151 | 1150 |
1152 return result; | 1151 return result; |
1153 } | 1152 } |
1154 | 1153 |
1155 //////////////////////////////////////////////////////////////////////////////// | 1154 //////////////////////////////////////////////////////////////////////////////// |
1156 | 1155 |
1157 void GrClipMaskManager::adjustPathStencilParams(const GrStencilAttachment* stenc
ilAttachment, | 1156 void GrClipMaskManager::adjustPathStencilParams(const GrStencilAttachment* stenc
ilAttachment, |
1158 GrStencilSettings* settings) { | 1157 GrStencilSettings* settings) { |
1159 if (stencilAttachment) { | 1158 if (stencilAttachment) { |
1160 int stencilBits = stencilAttachment->bits(); | 1159 int stencilBits = stencilAttachment->bits(); |
1161 this->adjustStencilParams(settings, fClipMode, stencilBits); | 1160 this->adjustStencilParams(settings, fClipMode, stencilBits); |
1162 } | 1161 } |
1163 } | 1162 } |
OLD | NEW |