Insert clip fragment processor outside GrCMM

Review URL: https://codereview.chromium.org/1393553002
This commit is contained in:
bsalomon 2015-10-07 09:20:28 -07:00 committed by Commit bot
parent 5ea95df02d
commit 0ba8c2401e
8 changed files with 126 additions and 100 deletions

View File

@ -116,7 +116,7 @@ protected:
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]),

View File

@ -208,7 +208,7 @@ GrTexture* GaussianBlur(GrContext* context,
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,

View File

@ -185,7 +185,7 @@ bool SkXfermodeImageFilter::filterImageGPU(Proxy* proxy,
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,

View File

@ -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);
}
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 @@ 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;
}

View File

@ -23,6 +23,25 @@ class GrPathRenderer;
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 @@ public:
* 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 @@ private:
// 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 @@ private:
kAlpha_ClipMaskType,
} fCurrClipMaskType;
static const int kMaxAnalyticElements = 4;
GrDrawTarget* fDrawTarget; // This is our owning draw target.
StencilClipMode fClipMode;

View File

@ -146,12 +146,17 @@ void GrDrawTarget::reset() {
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 @@ void GrDrawTarget::stencilPath(const GrPipelineBuilder& pipelineBuilder,
// 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 @@ void GrDrawTarget::drawPathBatch(const GrPipelineBuilder& pipelineBuilder,
// 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();

View File

@ -215,12 +215,12 @@ void GrGLTextureDomainEffect::GenKey(const GrProcessor& processor, const GrGLSLC
///////////////////////////////////////////////////////////////////////////////
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 @@ GrTextureDomainEffect::GrTextureDomainEffect(GrTexture* texture,
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 GrFragmentProcessor* GrTextureDomainEffect::TestCreate(GrProcessorTestData
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);
}

View File

@ -160,12 +160,12 @@ protected:
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();