Insert clip fragment processor outside GrCMM
Review URL: https://codereview.chromium.org/1393553002
This commit is contained in:
parent
5ea95df02d
commit
0ba8c2401e
@ -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]),
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user