| Index: src/gpu/GrClipMaskManager.cpp
|
| diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp
|
| index dadd2ea7b24030e239a35fd209f7d2ee95b23dbd..4af96ac421538a136e0dfce7c832bc22e096e3b4 100644
|
| --- a/src/gpu/GrClipMaskManager.cpp
|
| +++ b/src/gpu/GrClipMaskManager.cpp
|
| @@ -27,16 +27,9 @@
|
| typedef SkClipStack::Element Element;
|
|
|
| ////////////////////////////////////////////////////////////////////////////////
|
| -namespace {
|
| // set up the draw state to enable the aa clipping mask. Besides setting up the
|
| // stage matrix this also alters the vertex layout
|
| -void setup_drawstate_aaclip(const GrPipelineBuilder& pipelineBuilder,
|
| - GrTexture* result,
|
| - GrPipelineBuilder::AutoRestoreFragmentProcessorState* arfps,
|
| - const SkIRect &devBound) {
|
| - SkASSERT(arfps);
|
| - arfps->set(&pipelineBuilder);
|
| -
|
| +static const GrFragmentProcessor* create_fp_for_mask(GrTexture* result, const SkIRect &devBound) {
|
| SkMatrix mat;
|
| // We use device coords to compute the texture coordinates. We set our matrix to be a
|
| // translation to the devBound, and then a scaling matrix to normalized coords.
|
| @@ -45,23 +38,21 @@ void setup_drawstate_aaclip(const GrPipelineBuilder& pipelineBuilder,
|
| SkIntToScalar(-devBound.fTop));
|
|
|
| SkIRect domainTexels = SkIRect::MakeWH(devBound.width(), devBound.height());
|
| - // This could be a long-lived effect that is cached with the alpha-mask.
|
| - arfps->addCoverageFragmentProcessor(
|
| - GrTextureDomainEffect::Create(result,
|
| - mat,
|
| - GrTextureDomain::MakeTexelDomain(result, domainTexels),
|
| - GrTextureDomain::kDecal_Mode,
|
| - GrTextureParams::kNone_FilterMode,
|
| - kDevice_GrCoordSet))->unref();
|
| + return GrTextureDomainEffect::Create(result,
|
| + mat,
|
| + GrTextureDomain::MakeTexelDomain(result, domainTexels),
|
| + GrTextureDomain::kDecal_Mode,
|
| + GrTextureParams::kNone_FilterMode,
|
| + kDevice_GrCoordSet);
|
| }
|
|
|
| -bool path_needs_SW_renderer(GrContext* context,
|
| - const GrDrawTarget* gpu,
|
| - const GrPipelineBuilder& pipelineBuilder,
|
| - const SkMatrix& viewMatrix,
|
| - const SkPath& origPath,
|
| - const GrStrokeInfo& stroke,
|
| - bool doAA) {
|
| +static bool path_needs_SW_renderer(GrContext* context,
|
| + const GrDrawTarget* gpu,
|
| + const GrPipelineBuilder& pipelineBuilder,
|
| + const SkMatrix& viewMatrix,
|
| + const SkPath& origPath,
|
| + const GrStrokeInfo& stroke,
|
| + bool doAA) {
|
| // the gpu alpha mask will draw the inverse paths as non-inverse to a temp buffer
|
| SkTCopyOnFirstWrite<SkPath> path(origPath);
|
| if (path->isInverseFillType()) {
|
| @@ -75,7 +66,6 @@ bool path_needs_SW_renderer(GrContext* context,
|
| return nullptr == context->getPathRenderer(gpu, &pipelineBuilder, viewMatrix, *path, stroke,
|
| false, type);
|
| }
|
| -}
|
|
|
| GrClipMaskManager::GrClipMaskManager(GrDrawTarget* drawTarget)
|
| : fCurrClipMaskType(kNone_ClipMaskType)
|
| @@ -119,20 +109,21 @@ bool GrClipMaskManager::useSWOnlyPath(const GrPipelineBuilder& pipelineBuilder,
|
| return false;
|
| }
|
|
|
| -bool GrClipMaskManager::installClipEffects(
|
| - const GrPipelineBuilder& pipelineBuilder,
|
| - GrPipelineBuilder::AutoRestoreFragmentProcessorState* arfps,
|
| - const GrReducedClip::ElementList& elements,
|
| - const SkVector& clipToRTOffset,
|
| - const SkRect* drawBounds) {
|
| +const GrFragmentProcessor* GrClipMaskManager::getAnalyticClipProcessor(
|
| + const GrReducedClip::ElementList& elements,
|
| + const SkVector& clipToRTOffset,
|
| + const SkRect* drawBounds) {
|
| SkRect boundsInClipSpace;
|
| if (drawBounds) {
|
| boundsInClipSpace = *drawBounds;
|
| boundsInClipSpace.offset(-clipToRTOffset.fX, -clipToRTOffset.fY);
|
| }
|
| -
|
| - arfps->set(&pipelineBuilder);
|
| - GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
|
| + SkASSERT(elements.count() <= kMaxAnalyticElements);
|
| + const GrFragmentProcessor* fps[kMaxAnalyticElements];
|
| + for (int i = 0; i < kMaxAnalyticElements; ++i) {
|
| + fps[i] = nullptr;
|
| + }
|
| + int fpCnt = 0;
|
| GrReducedClip::ElementList::Iter iter(elements);
|
| bool failed = false;
|
| while (iter.get()) {
|
| @@ -165,62 +156,59 @@ bool GrClipMaskManager::installClipEffects(
|
| if (!skip) {
|
| GrPrimitiveEdgeType edgeType;
|
| if (iter.get()->isAA()) {
|
| - if (rt->isUnifiedMultisampled()) {
|
| - // Coverage based AA clips don't place nicely with MSAA.
|
| - failed = true;
|
| - break;
|
| - }
|
| edgeType =
|
| - invert ? kInverseFillAA_GrProcessorEdgeType : kFillAA_GrProcessorEdgeType;
|
| + invert ? kInverseFillAA_GrProcessorEdgeType : kFillAA_GrProcessorEdgeType;
|
| } else {
|
| - edgeType = invert ? kInverseFillBW_GrProcessorEdgeType :
|
| - kFillBW_GrProcessorEdgeType;
|
| + edgeType =
|
| + invert ? kInverseFillBW_GrProcessorEdgeType : kFillBW_GrProcessorEdgeType;
|
| }
|
| - SkAutoTUnref<GrFragmentProcessor> fp;
|
| switch (iter.get()->getType()) {
|
| case SkClipStack::Element::kPath_Type:
|
| - fp.reset(GrConvexPolyEffect::Create(edgeType, iter.get()->getPath(),
|
| - &clipToRTOffset));
|
| + fps[fpCnt] = GrConvexPolyEffect::Create(edgeType, iter.get()->getPath(),
|
| + &clipToRTOffset);
|
| break;
|
| case SkClipStack::Element::kRRect_Type: {
|
| SkRRect rrect = iter.get()->getRRect();
|
| rrect.offset(clipToRTOffset.fX, clipToRTOffset.fY);
|
| - fp.reset(GrRRectEffect::Create(edgeType, rrect));
|
| + fps[fpCnt] = GrRRectEffect::Create(edgeType, rrect);
|
| break;
|
| }
|
| case SkClipStack::Element::kRect_Type: {
|
| SkRect rect = iter.get()->getRect();
|
| rect.offset(clipToRTOffset.fX, clipToRTOffset.fY);
|
| - fp.reset(GrConvexPolyEffect::Create(edgeType, rect));
|
| + fps[fpCnt] = GrConvexPolyEffect::Create(edgeType, rect);
|
| break;
|
| }
|
| default:
|
| break;
|
| }
|
| - if (fp) {
|
| - arfps->addCoverageFragmentProcessor(fp);
|
| - } else {
|
| + if (!fps[fpCnt]) {
|
| failed = true;
|
| break;
|
| }
|
| + fpCnt++;
|
| }
|
| iter.next();
|
| }
|
|
|
| - if (failed) {
|
| - arfps->set(nullptr);
|
| + const GrFragmentProcessor* resultFP = nullptr;
|
| + if (!failed) {
|
| + resultFP = GrFragmentProcessor::RunInSeries(fps, fpCnt);
|
| + }
|
| + for (int i = 0; i < fpCnt; ++i) {
|
| + fps[i]->unref();
|
| }
|
| - return !failed;
|
| + return resultFP;
|
| }
|
|
|
| ////////////////////////////////////////////////////////////////////////////////
|
| // sort out what kind of clip mask needs to be created: alpha, stencil,
|
| // scissor, or entirely software
|
| bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder,
|
| - GrPipelineBuilder::AutoRestoreFragmentProcessorState* arfps,
|
| GrPipelineBuilder::AutoRestoreStencil* ars,
|
| GrScissorState* scissorState,
|
| - const SkRect* devBounds) {
|
| + const SkRect* devBounds,
|
| + GrAppliedClip* out) {
|
| fCurrClipMaskType = kNone_ClipMaskType;
|
| if (kRespectClip_StencilClipMode == fClipMode) {
|
| fClipMode = kIgnoreClip_StencilClipMode;
|
| @@ -288,12 +276,16 @@ bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder,
|
| // when drawing rounded div borders. This could probably be tuned based on a
|
| // configuration's relative costs of switching RTs to generate a mask vs
|
| // longer shaders.
|
| - if (elements.count() <= 4) {
|
| + if (elements.count() <= kMaxAnalyticElements) {
|
| SkVector clipToRTOffset = { SkIntToScalar(-clip.origin().fX),
|
| SkIntToScalar(-clip.origin().fY) };
|
| + // When there are multiple color samples we want to do per-sample clipping, not compute
|
| + // a fractional pixel coverage.
|
| + bool disallowAnalyticAA = pipelineBuilder.getRenderTarget()->isUnifiedMultisampled();
|
| + const GrFragmentProcessor* clipFP = nullptr;
|
| if (elements.isEmpty() ||
|
| - (requiresAA && this->installClipEffects(pipelineBuilder, arfps, elements, clipToRTOffset,
|
| - devBounds))) {
|
| + (requiresAA && !disallowAnalyticAA &&
|
| + SkToBool(clipFP = this->getAnalyticClipProcessor(elements, clipToRTOffset, devBounds)))) {
|
| SkIRect scissorSpaceIBounds(clipSpaceIBounds);
|
| scissorSpaceIBounds.offset(-clip.origin());
|
| if (nullptr == devBounds ||
|
| @@ -301,6 +293,7 @@ bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder,
|
| scissorState->set(scissorSpaceIBounds);
|
| }
|
| this->setPipelineBuilderStencil(pipelineBuilder, ars);
|
| + out->fClipCoverageFP.reset(clipFP);
|
| return true;
|
| }
|
| }
|
| @@ -332,12 +325,11 @@ bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder,
|
| }
|
|
|
| if (result) {
|
| - arfps->set(&pipelineBuilder);
|
| // The mask's top left coord should be pinned to the rounded-out top left corner of
|
| // clipSpace bounds. We determine the mask's position WRT to the render target here.
|
| SkIRect rtSpaceMaskBounds = clipSpaceIBounds;
|
| rtSpaceMaskBounds.offset(-clip.origin());
|
| - setup_drawstate_aaclip(pipelineBuilder, result, arfps, rtSpaceMaskBounds);
|
| + out->fClipCoverageFP.reset(create_fp_for_mask(result, rtSpaceMaskBounds));
|
| this->setPipelineBuilderStencil(pipelineBuilder, ars);
|
| return true;
|
| }
|
|
|