Insert clip fragment processor outside GrCMM
Review URL: https://codereview.chromium.org/1393553002
diff --git a/gm/texturedomaineffect.cpp b/gm/texturedomaineffect.cpp
index 77b51da..9952690 100644
--- a/gm/texturedomaineffect.cpp
+++ b/gm/texturedomaineffect.cpp
@@ -116,7 +116,7 @@
for (int m = 0; m < GrTextureDomain::kModeCount; ++m) {
GrTextureDomain::Mode mode = (GrTextureDomain::Mode) m;
GrPipelineBuilder pipelineBuilder;
- SkAutoTUnref<GrFragmentProcessor> fp(
+ SkAutoTUnref<const GrFragmentProcessor> fp(
GrTextureDomainEffect::Create(texture, textureMatrices[tm],
GrTextureDomain::MakeTexelDomain(texture,
texelDomains[d]),
diff --git a/src/effects/SkGpuBlurUtils.cpp b/src/effects/SkGpuBlurUtils.cpp
index 0ebbfe4..276fb6c 100644
--- a/src/effects/SkGpuBlurUtils.cpp
+++ b/src/effects/SkGpuBlurUtils.cpp
@@ -208,7 +208,7 @@
matrix.mapRect(&domain, rect);
domain.inset(i < scaleFactorX ? SK_ScalarHalf / srcTexture->width() : 0.0f,
i < scaleFactorY ? SK_ScalarHalf / srcTexture->height() : 0.0f);
- SkAutoTUnref<GrFragmentProcessor> fp(GrTextureDomainEffect::Create(
+ SkAutoTUnref<const GrFragmentProcessor> fp(GrTextureDomainEffect::Create(
srcTexture,
matrix,
domain,
diff --git a/src/effects/SkXfermodeImageFilter.cpp b/src/effects/SkXfermodeImageFilter.cpp
index af74c22..2311bb7 100644
--- a/src/effects/SkXfermodeImageFilter.cpp
+++ b/src/effects/SkXfermodeImageFilter.cpp
@@ -185,7 +185,7 @@
SkRect srcRect;
src.getBounds(&srcRect);
- SkAutoTUnref<GrFragmentProcessor> foregroundDomain(GrTextureDomainEffect::Create(
+ SkAutoTUnref<const GrFragmentProcessor> foregroundDomain(GrTextureDomainEffect::Create(
foregroundTex, foregroundMatrix,
GrTextureDomain::MakeTexelDomain(foregroundTex, foreground.bounds()),
GrTextureDomain::kDecal_Mode,
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp
index dadd2ea..4af96ac 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 @@
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 @@
return nullptr == context->getPathRenderer(gpu, &pipelineBuilder, viewMatrix, *path, stroke,
false, type);
}
-}
GrClipMaskManager::GrClipMaskManager(GrDrawTarget* drawTarget)
: fCurrClipMaskType(kNone_ClipMaskType)
@@ -119,20 +109,21 @@
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 @@
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);
}
- return !failed;
+ for (int i = 0; i < fpCnt; ++i) {
+ fps[i]->unref();
+ }
+ 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 @@
// 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 @@
scissorState->set(scissorSpaceIBounds);
}
this->setPipelineBuilderStencil(pipelineBuilder, ars);
+ out->fClipCoverageFP.reset(clipFP);
return true;
}
}
@@ -332,12 +325,11 @@
}
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;
}
diff --git a/src/gpu/GrClipMaskManager.h b/src/gpu/GrClipMaskManager.h
index 0c0c10c..5c336e0 100644
--- a/src/gpu/GrClipMaskManager.h
+++ b/src/gpu/GrClipMaskManager.h
@@ -23,6 +23,25 @@
class GrPathRendererChain;
class GrTexture;
class SkPath;
+
+/**
+ * Produced by GrClipMaskManager. It provides a set of modifications to the drawing state that
+ * are used to create the final GrPipeline for a GrBatch. This is a work in progress. It will
+ * eventually encapsulate all mechanisms for modifying the scissor, shaders, and stencil state
+ * to implement clipping.
+ */
+class GrAppliedClip : public SkNoncopyable {
+public:
+ GrAppliedClip() {}
+ const GrFragmentProcessor* clipCoverageFragmentProcessor() const { return fClipCoverageFP; }
+
+private:
+ SkAutoTUnref<const GrFragmentProcessor> fClipCoverageFP;
+ friend class GrClipMaskManager;
+
+ typedef SkNoncopyable INHERITED;
+};
+
/**
* The clip mask creator handles the generation of the clip mask. If anti
* aliasing is requested it will (in the future) generate a single channel
@@ -43,10 +62,10 @@
* clip. devBounds is optional but can help optimize clipping.
*/
bool setupClipping(const GrPipelineBuilder&,
- GrPipelineBuilder::AutoRestoreFragmentProcessorState*,
GrPipelineBuilder::AutoRestoreStencil*,
GrScissorState*,
- const SkRect* devBounds);
+ const SkRect* devBounds,
+ GrAppliedClip*);
bool isClipInStencil() const {
return kStencil_ClipMaskType == fCurrClipMaskType;
@@ -77,11 +96,9 @@
// Attempts to install a series of coverage effects to implement the clip. Return indicates
// whether the element list was successfully converted to effects.
- bool installClipEffects(const GrPipelineBuilder&,
- GrPipelineBuilder::AutoRestoreFragmentProcessorState*,
- const GrReducedClip::ElementList&,
- const SkVector& clipOffset,
- const SkRect* devBounds);
+ const GrFragmentProcessor* getAnalyticClipProcessor(const GrReducedClip::ElementList&,
+ const SkVector& clipOffset,
+ const SkRect* devBounds);
// Draws the clip into the stencil buffer
bool createStencilClipMask(GrRenderTarget*,
@@ -164,6 +181,8 @@
kAlpha_ClipMaskType,
} fCurrClipMaskType;
+ static const int kMaxAnalyticElements = 4;
+
GrDrawTarget* fDrawTarget; // This is our owning draw target.
StencilClipMode fClipMode;
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index 1edb48c..ba0142e 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -146,12 +146,17 @@
void GrDrawTarget::drawBatch(const GrPipelineBuilder& pipelineBuilder, GrDrawBatch* batch) {
// Setup clip
GrScissorState scissorState;
- GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps;
GrPipelineBuilder::AutoRestoreStencil ars;
- if (!fClipMaskManager->setupClipping(pipelineBuilder, &arfps, &ars, &scissorState,
- &batch->bounds())) {
+ GrAppliedClip clip;
+ if (!fClipMaskManager->setupClipping(pipelineBuilder, &ars, &scissorState, &batch->bounds(),
+ &clip)) {
return;
}
+ GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps;
+ if (clip.clipCoverageFragmentProcessor()) {
+ arfps.set(&pipelineBuilder);
+ arfps.addCoverageFragmentProcessor(clip.clipCoverageFragmentProcessor());
+ }
GrPipeline::CreateArgs args;
if (!this->installPipelineInDrawBatch(&pipelineBuilder, &scissorState, batch)) {
@@ -206,13 +211,18 @@
// Setup clip
GrScissorState scissorState;
- GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps;
GrPipelineBuilder::AutoRestoreStencil ars;
-
- if (!fClipMaskManager->setupClipping(pipelineBuilder, &arfps, &ars, &scissorState, nullptr)) {
+ GrAppliedClip clip;
+ if (!fClipMaskManager->setupClipping(pipelineBuilder, &ars, &scissorState, nullptr, &clip)) {
return;
}
+ GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps;
+ if (clip.clipCoverageFragmentProcessor()) {
+ arfps.set(&pipelineBuilder);
+ arfps.addCoverageFragmentProcessor(clip.clipCoverageFragmentProcessor());
+ }
+
// set stencil settings for path
GrStencilSettings stencilSettings;
GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
@@ -261,13 +271,19 @@
// batches.
GrScissorState scissorState;
- GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps;
GrPipelineBuilder::AutoRestoreStencil ars;
- if (!fClipMaskManager->setupClipping(pipelineBuilder, &arfps, &ars, &scissorState,
- &batch->bounds())) {
+ GrAppliedClip clip;
+ if (!fClipMaskManager->setupClipping(pipelineBuilder, &ars, &scissorState, &batch->bounds(),
+ &clip)) {
return;
}
+ GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps;
+ if (clip.clipCoverageFragmentProcessor()) {
+ arfps.set(&pipelineBuilder);
+ arfps.addCoverageFragmentProcessor(clip.clipCoverageFragmentProcessor());
+ }
+
// Ensure the render target has a stencil buffer and get the stencil settings.
GrStencilSettings stencilSettings;
GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
diff --git a/src/gpu/effects/GrTextureDomain.cpp b/src/gpu/effects/GrTextureDomain.cpp
index bf8bb59..ae0a614 100644
--- a/src/gpu/effects/GrTextureDomain.cpp
+++ b/src/gpu/effects/GrTextureDomain.cpp
@@ -215,12 +215,12 @@
///////////////////////////////////////////////////////////////////////////////
-GrFragmentProcessor* GrTextureDomainEffect::Create(GrTexture* texture,
- const SkMatrix& matrix,
- const SkRect& domain,
- GrTextureDomain::Mode mode,
- GrTextureParams::FilterMode filterMode,
- GrCoordSet coordSet) {
+const GrFragmentProcessor* GrTextureDomainEffect::Create(GrTexture* texture,
+ const SkMatrix& matrix,
+ const SkRect& domain,
+ GrTextureDomain::Mode mode,
+ GrTextureParams::FilterMode filterMode,
+ GrCoordSet coordSet) {
static const SkRect kFullRect = {0, 0, SK_Scalar1, SK_Scalar1};
if (GrTextureDomain::kIgnore_Mode == mode ||
(GrTextureDomain::kClamp_Mode == mode && domain.contains(kFullRect))) {
@@ -243,12 +243,10 @@
this->initClassID<GrTextureDomainEffect>();
}
-GrTextureDomainEffect::~GrTextureDomainEffect() {
-
-}
+GrTextureDomainEffect::~GrTextureDomainEffect() {}
void GrTextureDomainEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
- GrProcessorKeyBuilder* b) const {
+ GrProcessorKeyBuilder* b) const {
GrGLTextureDomainEffect::GenKey(*this, caps, b);
}
@@ -290,10 +288,11 @@
const SkMatrix& matrix = GrTest::TestMatrix(d->fRandom);
bool bilerp = mode != GrTextureDomain::kRepeat_Mode ? d->fRandom->nextBool() : false;
GrCoordSet coords = d->fRandom->nextBool() ? kLocal_GrCoordSet : kDevice_GrCoordSet;
- return GrTextureDomainEffect::Create(d->fTextures[texIdx],
- matrix,
- domain,
- mode,
- bilerp ? GrTextureParams::kBilerp_FilterMode : GrTextureParams::kNone_FilterMode,
- coords);
+ return GrTextureDomainEffect::Create(
+ d->fTextures[texIdx],
+ matrix,
+ domain,
+ mode,
+ bilerp ? GrTextureParams::kBilerp_FilterMode : GrTextureParams::kNone_FilterMode,
+ coords);
}
diff --git a/src/gpu/effects/GrTextureDomain.h b/src/gpu/effects/GrTextureDomain.h
index f0d180d..978a68c 100644
--- a/src/gpu/effects/GrTextureDomain.h
+++ b/src/gpu/effects/GrTextureDomain.h
@@ -160,12 +160,12 @@
class GrTextureDomainEffect : public GrSingleTextureEffect {
public:
- static GrFragmentProcessor* Create(GrTexture*,
- const SkMatrix&,
- const SkRect& domain,
- GrTextureDomain::Mode,
- GrTextureParams::FilterMode filterMode,
- GrCoordSet = kLocal_GrCoordSet);
+ static const GrFragmentProcessor* Create(GrTexture*,
+ const SkMatrix&,
+ const SkRect& domain,
+ GrTextureDomain::Mode,
+ GrTextureParams::FilterMode filterMode,
+ GrCoordSet = kLocal_GrCoordSet);
virtual ~GrTextureDomainEffect();