aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu
diff options
context:
space:
mode:
authorGravatar Brian Salomon <bsalomon@google.com>2018-01-23 10:30:17 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-01-23 18:28:46 +0000
commitb4e965c103c3140f0072949343befb34bceadc96 (patch)
tree71e989c6002dae88d3438d991996ad1f7725d6c9 /src/gpu
parente70b9e899c987a73d964b9b630c65523ad84717a (diff)
Revert "Revert "Use GrOvalOpFactory ops to draw non-AA rrects, ovals, and arcs.""
This reverts commit befff6580e9dc6b15bc6db3cc3f5fff22185cba8. Bug: skia: Change-Id: Ia108408cd986c03783af5058845790f6b17201f4 Reviewed-on: https://skia-review.googlesource.com/98703 Reviewed-by: Brian Salomon <bsalomon@google.com> Commit-Queue: Brian Salomon <bsalomon@google.com>
Diffstat (limited to 'src/gpu')
-rw-r--r--src/gpu/GrClipStackClip.cpp2
-rw-r--r--src/gpu/GrRenderTargetContext.cpp75
-rw-r--r--src/gpu/GrRenderTargetContext.h8
-rw-r--r--src/gpu/GrXferProcessor.cpp8
-rw-r--r--src/gpu/GrXferProcessor.h5
-rw-r--r--src/gpu/effects/GrCustomXfermode.cpp7
-rw-r--r--src/gpu/effects/GrPorterDuffXferProcessor.cpp5
-rw-r--r--src/gpu/effects/GrPorterDuffXferProcessor.h2
-rw-r--r--src/gpu/ops/GrOvalOpFactory.cpp223
-rw-r--r--src/gpu/ops/GrOvalOpFactory.h40
-rw-r--r--src/gpu/text/GrStencilAndCoverTextContext.cpp3
11 files changed, 258 insertions, 120 deletions
diff --git a/src/gpu/GrClipStackClip.cpp b/src/gpu/GrClipStackClip.cpp
index 8f82ea1228..2ce40c5149 100644
--- a/src/gpu/GrClipStackClip.cpp
+++ b/src/gpu/GrClipStackClip.cpp
@@ -124,6 +124,8 @@ bool GrClipStackClip::PathNeedsSWRenderer(GrContext* context,
canDrawArgs.fAAType = GrChooseAAType(GrAA(element->isAA()),
renderTargetContext->fsaaType(),
GrAllowMixedSamples::kYes,
+ GrAllowNonAABinaryCoverage::kNo,
+ nullptr,
*context->caps());
canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings;
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index d86bf80d63..6866ed579a 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -99,6 +99,7 @@ private:
//////////////////////////////////////////////////////////////////////////////
GrAAType GrChooseAAType(GrAA aa, GrFSAAType fsaaType, GrAllowMixedSamples allowMixedSamples,
+ GrAllowNonAABinaryCoverage allowNonAABinaryCoverage, const GrPaint* paint,
const GrCaps& caps) {
if (GrAA::kNo == aa) {
// On some devices we cannot disable MSAA if it is enabled so we make the AA type reflect
@@ -106,6 +107,34 @@ GrAAType GrChooseAAType(GrAA aa, GrFSAAType fsaaType, GrAllowMixedSamples allowM
if (fsaaType == GrFSAAType::kUnifiedMSAA && !caps.multisampleDisableSupport()) {
return GrAAType::kMSAA;
}
+ if (GrAllowNonAABinaryCoverage::kYes == allowNonAABinaryCoverage) {
+ SkASSERT(paint);
+ // If we already have a coverage FP then we won't make anything worse.
+ if (paint->numCoverageFragmentProcessors()) {
+ return GrAAType::kCoverage;
+ }
+ // Shader based blending isn't so expensive with these extensions.
+ if (caps.shaderCaps()->fbFetchSupport() || caps.textureBarrierSupport()) {
+ return GrAAType::kCoverage;
+ }
+ SkBlendMode mode;
+ if (GrXPFactory::AsBlendMode(paint->getXPFactory(), &mode)) {
+ // If we have dual source blending then all Porter-Duff modes can use HW blending
+ // with coverage.
+ if (mode <= SkBlendMode::kLastCoeffMode &&
+ caps.shaderCaps()->dualSourceBlendingSupport()) {
+ return GrAAType::kCoverage;
+ }
+ if (SkBlendMode_SupportsCoverageAsAlpha(mode)) {
+ return GrAAType::kCoverage;
+ }
+ // If the mode is "advanced" then either we will already be doing dst copies or we
+ // have advanced blending support and it is ok to conflate coverage with alpha.
+ if (mode > SkBlendMode::kLastCoeffMode) {
+ return GrAAType::kCoverage;
+ }
+ }
+ }
return GrAAType::kNone;
}
switch (fsaaType) {
@@ -915,14 +944,16 @@ void GrRenderTargetContext::drawRRect(const GrClip& origClip,
AutoCheckFlush acf(this->drawingManager());
const SkStrokeRec stroke = style.strokeRec();
- GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
+ GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo,
+ GrAllowNonAABinaryCoverage::kYes, &paint);
if (GrAAType::kCoverage == aaType) {
const GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
- std::unique_ptr<GrDrawOp> op = GrOvalOpFactory::MakeRRectOp(std::move(paint),
- viewMatrix,
- rrect,
- stroke,
- shaderCaps);
+ std::unique_ptr<GrDrawOp> op = GrOvalOpFactory::MakeCoverageRRectOp(std::move(paint),
+ aa,
+ viewMatrix,
+ rrect,
+ stroke,
+ shaderCaps);
if (op) {
this->addDrawOp(*clip, std::move(op));
return;
@@ -1163,8 +1194,9 @@ bool GrRenderTargetContext::drawFilledDRRect(const GrClip& clip,
auto circleBounds = SkRect::MakeLTRB(cx - avgR, cy - avgR, cx + avgR, cy + avgR);
SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
stroke.setStrokeStyle(outerR - innerR);
- auto op = GrOvalOpFactory::MakeOvalOp(std::move(paint), viewMatrix, circleBounds,
- stroke, this->caps()->shaderCaps());
+ auto op = GrOvalOpFactory::MakeCoverageOvalOp(std::move(paint), aa, viewMatrix,
+ circleBounds, stroke,
+ this->caps()->shaderCaps());
if (op) {
this->addDrawOp(clip, std::move(op));
return true;
@@ -1305,11 +1337,12 @@ void GrRenderTargetContext::drawOval(const GrClip& clip,
AutoCheckFlush acf(this->drawingManager());
const SkStrokeRec& stroke = style.strokeRec();
- GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
+ GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo,
+ GrAllowNonAABinaryCoverage::kYes, &paint);
if (GrAAType::kCoverage == aaType) {
const GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
- std::unique_ptr<GrDrawOp> op =
- GrOvalOpFactory::MakeOvalOp(std::move(paint), viewMatrix, oval, stroke, shaderCaps);
+ std::unique_ptr<GrDrawOp> op = GrOvalOpFactory::MakeCoverageOvalOp(
+ std::move(paint), aa, viewMatrix, oval, stroke, shaderCaps);
if (op) {
this->addDrawOp(clip, std::move(op));
return;
@@ -1336,17 +1369,19 @@ void GrRenderTargetContext::drawArc(const GrClip& clip,
AutoCheckFlush acf(this->drawingManager());
- GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
+ GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo,
+ GrAllowNonAABinaryCoverage::kYes, &paint);
if (GrAAType::kCoverage == aaType) {
const GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
- std::unique_ptr<GrDrawOp> op = GrOvalOpFactory::MakeArcOp(std::move(paint),
- viewMatrix,
- oval,
- startAngle,
- sweepAngle,
- useCenter,
- style,
- shaderCaps);
+ std::unique_ptr<GrDrawOp> op = GrOvalOpFactory::MakeCoverageArcOp(std::move(paint),
+ aa,
+ viewMatrix,
+ oval,
+ startAngle,
+ sweepAngle,
+ useCenter,
+ style,
+ shaderCaps);
if (op) {
this->addDrawOp(clip, std::move(op));
return;
diff --git a/src/gpu/GrRenderTargetContext.h b/src/gpu/GrRenderTargetContext.h
index 6e0c6745fd..bc1e69d0a0 100644
--- a/src/gpu/GrRenderTargetContext.h
+++ b/src/gpu/GrRenderTargetContext.h
@@ -385,8 +385,12 @@ protected:
private:
class TextTarget;
- inline GrAAType chooseAAType(GrAA aa, GrAllowMixedSamples allowMixedSamples) {
- return GrChooseAAType(aa, this->fsaaType(), allowMixedSamples, *this->caps());
+ GrAAType chooseAAType(
+ GrAA aa, GrAllowMixedSamples allowMixedSamples,
+ GrAllowNonAABinaryCoverage allowNonAABinaryCoverage = GrAllowNonAABinaryCoverage::kNo,
+ const GrPaint* paint = nullptr) {
+ return GrChooseAAType(aa, this->fsaaType(), allowMixedSamples, allowNonAABinaryCoverage,
+ paint, *this->caps());
}
friend class GrAtlasTextBlob; // for access to add[Mesh]DrawOp
diff --git a/src/gpu/GrXferProcessor.cpp b/src/gpu/GrXferProcessor.cpp
index 8f7377e0b2..39bec98ab5 100644
--- a/src/gpu/GrXferProcessor.cpp
+++ b/src/gpu/GrXferProcessor.cpp
@@ -193,3 +193,11 @@ sk_sp<const GrXferProcessor> GrXPFactory::MakeXferProcessor(const GrXPFactory* f
caps);
}
}
+
+bool GrXPFactory::AsBlendMode(const GrXPFactory* factory, SkBlendMode* mode) {
+ if (factory) {
+ return factory->asBlendMode(mode);
+ }
+ *mode = SkBlendMode::kSrcOver;
+ return true;
+}
diff --git a/src/gpu/GrXferProcessor.h b/src/gpu/GrXferProcessor.h
index 5ede1ae828..3aac2d3732 100644
--- a/src/gpu/GrXferProcessor.h
+++ b/src/gpu/GrXferProcessor.h
@@ -301,6 +301,9 @@ public:
const GrCaps&,
GrPixelConfigIsClamped);
+ /** If true mode will be the equivalent SkBlendMode for the XPFactory. */
+ static bool AsBlendMode(const GrXPFactory*, SkBlendMode* mode);
+
protected:
constexpr GrXPFactory() {}
@@ -319,6 +322,8 @@ private:
const GrProcessorAnalysisCoverage&,
const GrCaps&,
GrPixelConfigIsClamped) const = 0;
+
+ virtual bool asBlendMode(SkBlendMode*) const { return false; }
};
#if defined(__GNUC__)
#pragma GCC diagnostic pop
diff --git a/src/gpu/effects/GrCustomXfermode.cpp b/src/gpu/effects/GrCustomXfermode.cpp
index bdeda9467c..b43cea9a69 100644
--- a/src/gpu/effects/GrCustomXfermode.cpp
+++ b/src/gpu/effects/GrCustomXfermode.cpp
@@ -225,6 +225,8 @@ private:
const GrCaps&,
GrPixelConfigIsClamped) const override;
+ bool asBlendMode(SkBlendMode* mode) const override;
+
GR_DECLARE_XP_FACTORY_TEST
SkBlendMode fMode;
@@ -362,6 +364,11 @@ GrXPFactory::AnalysisProperties CustomXPFactory::analysisProperties(
AnalysisProperties::kReadsDstInShader;
}
+bool CustomXPFactory::asBlendMode(SkBlendMode* mode) const {
+ *mode = fMode;
+ return true;
+}
+
GR_DEFINE_XP_FACTORY_TEST(CustomXPFactory);
#if GR_TEST_UTILS
const GrXPFactory* CustomXPFactory::TestGet(GrProcessorTestData* d) {
diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.cpp b/src/gpu/effects/GrPorterDuffXferProcessor.cpp
index f4af7a4679..c8f11e0f5d 100644
--- a/src/gpu/effects/GrPorterDuffXferProcessor.cpp
+++ b/src/gpu/effects/GrPorterDuffXferProcessor.cpp
@@ -861,6 +861,11 @@ GrXPFactory::AnalysisProperties GrPorterDuffXPFactory::analysisProperties(
return analysis_properties(color, coverage, caps, dstIsClamped, fBlendMode);
}
+bool GrPorterDuffXPFactory::asBlendMode(SkBlendMode* mode) const {
+ *mode = fBlendMode;
+ return true;
+}
+
GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory);
#if GR_TEST_UTILS
diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.h b/src/gpu/effects/GrPorterDuffXferProcessor.h
index 74ae1533bf..8241a9f1ab 100644
--- a/src/gpu/effects/GrPorterDuffXferProcessor.h
+++ b/src/gpu/effects/GrPorterDuffXferProcessor.h
@@ -58,6 +58,8 @@ private:
const GrCaps&,
GrPixelConfigIsClamped) const override;
+ bool asBlendMode(SkBlendMode* mode) const override;
+
GR_DECLARE_XP_FACTORY_TEST
static void TestGetXPOutputTypes(const GrXferProcessor*, int* outPrimary, int* outSecondary);
diff --git a/src/gpu/ops/GrOvalOpFactory.cpp b/src/gpu/ops/GrOvalOpFactory.cpp
index 9194f673e6..e5f1abf9f2 100644
--- a/src/gpu/ops/GrOvalOpFactory.cpp
+++ b/src/gpu/ops/GrOvalOpFactory.cpp
@@ -66,10 +66,12 @@ static inline bool circle_stays_circle(const SkMatrix& m) { return m.isSimilarit
class CircleGeometryProcessor : public GrGeometryProcessor {
public:
- CircleGeometryProcessor(bool stroke, bool clipPlane, bool isectPlane, bool unionPlane,
+ CircleGeometryProcessor(bool stroke, bool clipPlane, bool isectPlane, bool unionPlane, GrAA aa,
const SkMatrix& localMatrix)
: INHERITED(kCircleGeometryProcessor_ClassID)
- , fLocalMatrix(localMatrix) {
+ , fLocalMatrix(localMatrix)
+ , fStroke(stroke)
+ , fAA(aa) {
fInPosition = &this->addVertexAttrib("inPosition", kFloat2_GrVertexAttribType);
fInColor = &this->addVertexAttrib("inColor", kUByte4_norm_GrVertexAttribType);
fInCircleEdge = &this->addVertexAttrib("inCircleEdge", kFloat4_GrVertexAttribType);
@@ -88,7 +90,6 @@ public:
} else {
fInUnionPlane = nullptr;
}
- fStroke = stroke;
}
~CircleGeometryProcessor() override {}
@@ -174,7 +175,16 @@ private:
}
fragBuilder->codeAppend("edgeAlpha *= clip;");
}
- fragBuilder->codeAppendf("%s = half4(edgeAlpha);", args.fOutputCoverage);
+ if (GrAA::kYes == cgp.fAA) {
+ fragBuilder->codeAppendf("%s = half4(edgeAlpha);", args.fOutputCoverage);
+ } else {
+ // Using a value less than half is a bit of a hack. If 0.5 is used then filling
+ // a set of abutting arcs that should create a full circle can leave gaps at pixels
+ // that neither arc quite owns. Generally speaking, double hitting these pixels
+ // instead of missing them looks better.
+ fragBuilder->codeAppendf("%s = edgeAlpha > 0.4999 ? half4(1) : half4(0);",
+ args.fOutputCoverage);
+ }
}
static void GenKey(const GrGeometryProcessor& gp,
@@ -187,6 +197,7 @@ private:
key |= cgp.fInClipPlane ? 0x04 : 0x0;
key |= cgp.fInIsectPlane ? 0x08 : 0x0;
key |= cgp.fInUnionPlane ? 0x10 : 0x0;
+ key |= GrAA::kYes == cgp.fAA ? 0x20 : 0x0;
b->add32(key);
}
@@ -208,6 +219,7 @@ private:
const Attribute* fInIsectPlane;
const Attribute* fInUnionPlane;
bool fStroke;
+ GrAA fAA;
GR_DECLARE_GEOMETRY_PROCESSOR_TEST
@@ -218,9 +230,10 @@ GR_DEFINE_GEOMETRY_PROCESSOR_TEST(CircleGeometryProcessor);
#if GR_TEST_UTILS
sk_sp<GrGeometryProcessor> CircleGeometryProcessor::TestCreate(GrProcessorTestData* d) {
+ GrAA aa = d->fRandom->nextBool() ? GrAA::kYes : GrAA::kNo;
return sk_sp<GrGeometryProcessor>(new CircleGeometryProcessor(
d->fRandom->nextBool(), d->fRandom->nextBool(), d->fRandom->nextBool(),
- d->fRandom->nextBool(), GrTest::TestMatrix(d->fRandom)));
+ d->fRandom->nextBool(), aa, GrTest::TestMatrix(d->fRandom)));
}
#endif
@@ -236,14 +249,15 @@ sk_sp<GrGeometryProcessor> CircleGeometryProcessor::TestCreate(GrProcessorTestDa
class EllipseGeometryProcessor : public GrGeometryProcessor {
public:
- EllipseGeometryProcessor(bool stroke, const SkMatrix& localMatrix)
- : INHERITED(kEllipseGeometryProcessor_ClassID)
- , fLocalMatrix(localMatrix) {
+ EllipseGeometryProcessor(bool stroke, GrAA aa, const SkMatrix& localMatrix)
+ : INHERITED(kEllipseGeometryProcessor_ClassID)
+ , fLocalMatrix(localMatrix)
+ , fStroke(stroke)
+ , fAA(aa) {
fInPosition = &this->addVertexAttrib("inPosition", kFloat2_GrVertexAttribType);
fInColor = &this->addVertexAttrib("inColor", kUByte4_norm_GrVertexAttribType);
fInEllipseOffset = &this->addVertexAttrib("inEllipseOffset", kHalf2_GrVertexAttribType);
fInEllipseRadii = &this->addVertexAttrib("inEllipseRadii", kHalf4_GrVertexAttribType);
- fStroke = stroke;
}
~EllipseGeometryProcessor() override {}
@@ -318,7 +332,12 @@ private:
fragBuilder->codeAppend("edgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);");
}
- fragBuilder->codeAppendf("%s = half4(edgeAlpha);", args.fOutputCoverage);
+ if (GrAA::kYes == egp.fAA) {
+ fragBuilder->codeAppendf("%s = half4(edgeAlpha);", args.fOutputCoverage);
+ } else {
+ fragBuilder->codeAppendf("%s = edgeAlpha > 0.5 ? half4(1) : half4(0);",
+ args.fOutputCoverage);
+ }
}
static void GenKey(const GrGeometryProcessor& gp,
@@ -327,6 +346,7 @@ private:
const EllipseGeometryProcessor& egp = gp.cast<EllipseGeometryProcessor>();
uint16_t key = egp.fStroke ? 0x1 : 0x0;
key |= egp.fLocalMatrix.hasPerspective() ? 0x2 : 0x0;
+ key |= GrAA::kYes == egp.fAA ? 0x4 : 0x0;
b->add32(key);
}
@@ -346,6 +366,7 @@ private:
const Attribute* fInEllipseRadii;
SkMatrix fLocalMatrix;
bool fStroke;
+ GrAA fAA;
GR_DECLARE_GEOMETRY_PROCESSOR_TEST
@@ -356,8 +377,9 @@ GR_DEFINE_GEOMETRY_PROCESSOR_TEST(EllipseGeometryProcessor);
#if GR_TEST_UTILS
sk_sp<GrGeometryProcessor> EllipseGeometryProcessor::TestCreate(GrProcessorTestData* d) {
- return sk_sp<GrGeometryProcessor>(
- new EllipseGeometryProcessor(d->fRandom->nextBool(), GrTest::TestMatrix(d->fRandom)));
+ GrAA aa = d->fRandom->nextBool() ? GrAA::kYes : GrAA::kNo;
+ return sk_sp<GrGeometryProcessor>(new EllipseGeometryProcessor(d->fRandom->nextBool(), aa,
+ GrTest::TestMatrix(d->fRandom)));
}
#endif
@@ -376,14 +398,15 @@ enum class DIEllipseStyle { kStroke = 0, kHairline, kFill };
class DIEllipseGeometryProcessor : public GrGeometryProcessor {
public:
- DIEllipseGeometryProcessor(const SkMatrix& viewMatrix, DIEllipseStyle style)
+ DIEllipseGeometryProcessor(const SkMatrix& viewMatrix, DIEllipseStyle style, GrAA aa)
: INHERITED(kDIEllipseGeometryProcessor_ClassID)
- , fViewMatrix(viewMatrix) {
+ , fViewMatrix(viewMatrix)
+ , fStyle(style)
+ , fAA(aa) {
fInPosition = &this->addVertexAttrib("inPosition", kFloat2_GrVertexAttribType);
fInColor = &this->addVertexAttrib("inColor", kUByte4_norm_GrVertexAttribType);
fInEllipseOffsets0 = &this->addVertexAttrib("inEllipseOffsets0", kHalf2_GrVertexAttribType);
fInEllipseOffsets1 = &this->addVertexAttrib("inEllipseOffsets1", kHalf2_GrVertexAttribType);
- fStyle = style;
}
~DIEllipseGeometryProcessor() override {}
@@ -473,8 +496,12 @@ private:
fragBuilder->codeAppend("invlen = inversesqrt(dot(grad, grad));");
fragBuilder->codeAppend("edgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);");
}
-
- fragBuilder->codeAppendf("%s = half4(edgeAlpha);", args.fOutputCoverage);
+ if (GrAA::kYes == diegp.fAA) {
+ fragBuilder->codeAppendf("%s = half4(edgeAlpha);", args.fOutputCoverage);
+ } else {
+ fragBuilder->codeAppendf("%s = edgeAlpha > 0.5 ? half4(1) : half4(0);",
+ args.fOutputCoverage);
+ }
}
static void GenKey(const GrGeometryProcessor& gp,
@@ -482,6 +509,7 @@ private:
GrProcessorKeyBuilder* b) {
const DIEllipseGeometryProcessor& diegp = gp.cast<DIEllipseGeometryProcessor>();
uint16_t key = static_cast<uint16_t>(diegp.fStyle);
+ key |= GrAA::kYes == diegp.fAA ? 0x80 : 0x0;
key |= ComputePosKey(diegp.fViewMatrix) << 10;
b->add32(key);
}
@@ -512,6 +540,7 @@ private:
const Attribute* fInEllipseOffsets1;
SkMatrix fViewMatrix;
DIEllipseStyle fStyle;
+ GrAA fAA;
GR_DECLARE_GEOMETRY_PROCESSOR_TEST
@@ -522,8 +551,9 @@ GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DIEllipseGeometryProcessor);
#if GR_TEST_UTILS
sk_sp<GrGeometryProcessor> DIEllipseGeometryProcessor::TestCreate(GrProcessorTestData* d) {
+ GrAA aa = d->fRandom->nextBool() ? GrAA::kYes : GrAA::kNo;
return sk_sp<GrGeometryProcessor>(new DIEllipseGeometryProcessor(
- GrTest::TestMatrix(d->fRandom), (DIEllipseStyle)(d->fRandom->nextRangeU(0, 2))));
+ GrTest::TestMatrix(d->fRandom), (DIEllipseStyle)(d->fRandom->nextRangeU(0, 2)), aa));
}
#endif
@@ -591,7 +621,7 @@ public:
bool fUseCenter;
};
- static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkMatrix& viewMatrix,
+ static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix,
SkPoint center, SkScalar radius, const GrStyle& style,
const ArcParams* arcParams = nullptr) {
SkASSERT(circle_stays_circle(viewMatrix));
@@ -618,13 +648,13 @@ public:
break;
}
}
- return Helper::FactoryHelper<CircleOp>(std::move(paint), viewMatrix, center, radius, style,
- arcParams);
+ return Helper::FactoryHelper<CircleOp>(std::move(paint), aa, viewMatrix, center, radius,
+ style, arcParams);
}
- CircleOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkMatrix& viewMatrix,
+ CircleOp(const Helper::MakeArgs& helperArgs, GrColor color, GrAA aa, const SkMatrix& viewMatrix,
SkPoint center, SkScalar radius, const GrStyle& style, const ArcParams* arcParams)
- : GrMeshDrawOp(ClassID()), fHelper(helperArgs, GrAAType::kCoverage) {
+ : GrMeshDrawOp(ClassID()), fHelper(helperArgs, GrAAType::kCoverage), fAA(aa) {
const SkStrokeRec& stroke = style.strokeRec();
SkStrokeRec::Style recStyle = stroke.getStyle();
@@ -816,7 +846,7 @@ private:
// Setup geometry processor
sk_sp<GrGeometryProcessor> gp(new CircleGeometryProcessor(
- !fAllFill, fClipPlane, fClipPlaneIsect, fClipPlaneUnion, localMatrix));
+ !fAllFill, fClipPlane, fClipPlaneIsect, fClipPlaneUnion, fAA, localMatrix));
struct CircleVertex {
SkPoint fPos;
@@ -1105,6 +1135,10 @@ private:
return false;
}
+ if (fAA != that->fAA) {
+ return false;
+ }
+
// Because we've set up the ops that don't use the planes with noop values
// we can just accumulate used planes by later ops.
fClipPlane |= that->fClipPlane;
@@ -1139,6 +1173,7 @@ private:
bool fClipPlane;
bool fClipPlaneIsect;
bool fClipPlaneUnion;
+ GrAA fAA;
typedef GrMeshDrawOp INHERITED;
};
@@ -1160,7 +1195,7 @@ private:
public:
DEFINE_OP_CLASS_ID
- static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkMatrix& viewMatrix,
+ static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix,
const SkRect& ellipse, const SkStrokeRec& stroke) {
DeviceSpaceParams params;
// do any matrix crunching before we reset the draw state for device coords
@@ -1219,12 +1254,13 @@ public:
params.fXRadius += scaledStroke.fX;
params.fYRadius += scaledStroke.fY;
}
- return Helper::FactoryHelper<EllipseOp>(std::move(paint), viewMatrix, params, stroke);
+ return Helper::FactoryHelper<EllipseOp>(std::move(paint), aa, viewMatrix, params, stroke);
}
- EllipseOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkMatrix& viewMatrix,
- const DeviceSpaceParams& params, const SkStrokeRec& stroke)
- : INHERITED(ClassID()), fHelper(helperArgs, GrAAType::kCoverage) {
+ EllipseOp(const Helper::MakeArgs& helperArgs, GrColor color, GrAA aa,
+ const SkMatrix& viewMatrix, const DeviceSpaceParams& params,
+ const SkStrokeRec& stroke)
+ : INHERITED(ClassID()), fHelper(helperArgs, GrAAType::kCoverage), fAA(aa) {
SkStrokeRec::Style style = stroke.getStyle();
bool isStrokeOnly =
SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style;
@@ -1284,7 +1320,7 @@ private:
}
// Setup geometry processor
- sk_sp<GrGeometryProcessor> gp(new EllipseGeometryProcessor(fStroked, localMatrix));
+ sk_sp<GrGeometryProcessor> gp(new EllipseGeometryProcessor(fStroked, fAA, localMatrix));
QuadHelper helper;
size_t vertexStride = gp->getVertexStride();
@@ -1356,6 +1392,10 @@ private:
return false;
}
+ if (fAA != that->fAA) {
+ return false;
+ }
+
fEllipses.push_back_n(that->fEllipses.count(), that->fEllipses.begin());
this->joinBounds(*that);
return true;
@@ -1373,6 +1413,7 @@ private:
SkMatrix fViewMatrixIfUsingLocalCoords;
Helper fHelper;
bool fStroked;
+ GrAA fAA;
SkSTArray<1, Ellipse, true> fEllipses;
typedef GrMeshDrawOp INHERITED;
@@ -1396,7 +1437,7 @@ private:
public:
DEFINE_OP_CLASS_ID
- static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkMatrix& viewMatrix,
+ static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix,
const SkRect& ellipse, const SkStrokeRec& stroke) {
DeviceSpaceParams params;
params.fCenter = SkPoint::Make(ellipse.centerX(), ellipse.centerY());
@@ -1451,12 +1492,12 @@ public:
(params.fInnerXRadius <= 0 || params.fInnerYRadius <= 0)) {
params.fStyle = DIEllipseStyle::kFill;
}
- return Helper::FactoryHelper<DIEllipseOp>(std::move(paint), params, viewMatrix);
+ return Helper::FactoryHelper<DIEllipseOp>(std::move(paint), aa, params, viewMatrix);
}
- DIEllipseOp(Helper::MakeArgs& helperArgs, GrColor color, const DeviceSpaceParams& params,
- const SkMatrix& viewMatrix)
- : INHERITED(ClassID()), fHelper(helperArgs, GrAAType::kCoverage) {
+ DIEllipseOp(Helper::MakeArgs& helperArgs, GrColor color, GrAA aa,
+ const DeviceSpaceParams& params, const SkMatrix& viewMatrix)
+ : INHERITED(ClassID()), fHelper(helperArgs, GrAAType::kCoverage), fAA(aa) {
// This expands the outer rect so that after CTM we end up with a half-pixel border
SkScalar a = viewMatrix[SkMatrix::kMScaleX];
SkScalar b = viewMatrix[SkMatrix::kMSkewX];
@@ -1511,7 +1552,7 @@ private:
void onPrepareDraws(Target* target) override {
// Setup geometry processor
sk_sp<GrGeometryProcessor> gp(
- new DIEllipseGeometryProcessor(this->viewMatrix(), this->style()));
+ new DIEllipseGeometryProcessor(this->viewMatrix(), this->style(), fAA));
size_t vertexStride = gp->getVertexStride();
SkASSERT(vertexStride == sizeof(DIEllipseVertex));
@@ -1576,6 +1617,10 @@ private:
return false;
}
+ if (fAA != that->fAA) {
+ return false;
+ }
+
fEllipses.push_back_n(that->fEllipses.count(), that->fEllipses.begin());
this->joinBounds(*that);
return true;
@@ -1599,6 +1644,7 @@ private:
Helper fHelper;
SkSTArray<1, Ellipse, true> fEllipses;
+ GrAA fAA;
typedef GrMeshDrawOp INHERITED;
};
@@ -1738,17 +1784,19 @@ public:
// A devStrokeWidth <= 0 indicates a fill only. If devStrokeWidth > 0 then strokeOnly indicates
// whether the rrect is only stroked or stroked and filled.
- static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkMatrix& viewMatrix,
+ static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix,
const SkRect& devRect, float devRadius,
float devStrokeWidth, bool strokeOnly) {
- return Helper::FactoryHelper<CircularRRectOp>(std::move(paint), viewMatrix, devRect,
+ return Helper::FactoryHelper<CircularRRectOp>(std::move(paint), aa, viewMatrix, devRect,
devRadius, devStrokeWidth, strokeOnly);
}
- CircularRRectOp(Helper::MakeArgs& helperArgs, GrColor color, const SkMatrix& viewMatrix,
- const SkRect& devRect, float devRadius, float devStrokeWidth, bool strokeOnly)
+ CircularRRectOp(Helper::MakeArgs& helperArgs, GrColor color, GrAA aa,
+ const SkMatrix& viewMatrix, const SkRect& devRect, float devRadius,
+ float devStrokeWidth, bool strokeOnly)
: INHERITED(ClassID())
, fViewMatrixIfUsingLocalCoords(viewMatrix)
- , fHelper(helperArgs, GrAAType::kCoverage) {
+ , fHelper(helperArgs, GrAAType::kCoverage)
+ , fAA(aa) {
SkRect bounds = devRect;
SkASSERT(!(devStrokeWidth <= 0 && strokeOnly));
SkScalar innerRadius = 0.0f;
@@ -1910,7 +1958,7 @@ private:
// Setup geometry processor
sk_sp<GrGeometryProcessor> gp(
- new CircleGeometryProcessor(!fAllFill, false, false, false, localMatrix));
+ new CircleGeometryProcessor(!fAllFill, false, false, false, fAA, localMatrix));
size_t vertexStride = gp->getVertexStride();
SkASSERT(sizeof(CircleVertex) == vertexStride);
@@ -2029,6 +2077,10 @@ private:
return false;
}
+ if (fAA != that->fAA) {
+ return false;
+ }
+
fRRects.push_back_n(that->fRRects.count(), that->fRRects.begin());
this->joinBounds(*that);
fVertCount += that->fVertCount;
@@ -2050,6 +2102,7 @@ private:
int fVertCount;
int fIndexCount;
bool fAllFill;
+ GrAA fAA;
SkSTArray<1, RRect, true> fRRects;
typedef GrMeshDrawOp INHERITED;
@@ -2087,7 +2140,7 @@ public:
// If devStrokeWidths values are <= 0 indicates then fill only. Otherwise, strokeOnly indicates
// whether the rrect is only stroked or stroked and filled.
- static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkMatrix& viewMatrix,
+ static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix,
const SkRect& devRect, float devXRadius, float devYRadius,
SkVector devStrokeWidths, bool strokeOnly) {
SkASSERT(devXRadius > 0.5);
@@ -2118,15 +2171,15 @@ public:
return nullptr;
}
}
- return Helper::FactoryHelper<EllipticalRRectOp>(std::move(paint), viewMatrix, devRect,
+ return Helper::FactoryHelper<EllipticalRRectOp>(std::move(paint), aa, viewMatrix, devRect,
devXRadius, devYRadius, devStrokeWidths,
strokeOnly);
}
- EllipticalRRectOp(Helper::MakeArgs helperArgs, GrColor color, const SkMatrix& viewMatrix,
- const SkRect& devRect, float devXRadius, float devYRadius,
- SkVector devStrokeHalfWidths, bool strokeOnly)
- : INHERITED(ClassID()), fHelper(helperArgs, GrAAType::kCoverage) {
+ EllipticalRRectOp(Helper::MakeArgs helperArgs, GrColor color, GrAA aa,
+ const SkMatrix& viewMatrix, const SkRect& devRect, float devXRadius,
+ float devYRadius, SkVector devStrokeHalfWidths, bool strokeOnly)
+ : INHERITED(ClassID()), fHelper(helperArgs, GrAAType::kCoverage), fAA(aa) {
SkScalar innerXRadius = 0.0f;
SkScalar innerYRadius = 0.0f;
SkRect bounds = devRect;
@@ -2192,7 +2245,7 @@ private:
}
// Setup geometry processor
- sk_sp<GrGeometryProcessor> gp(new EllipseGeometryProcessor(fStroked, localMatrix));
+ sk_sp<GrGeometryProcessor> gp(new EllipseGeometryProcessor(fStroked, fAA, localMatrix));
size_t vertexStride = gp->getVertexStride();
SkASSERT(vertexStride == sizeof(EllipseVertex));
@@ -2280,7 +2333,9 @@ private:
!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsingLocalCoords)) {
return false;
}
-
+ if (fAA != that->fAA) {
+ return false;
+ }
fRRects.push_back_n(that->fRRects.count(), that->fRRects.begin());
this->joinBounds(*that);
return true;
@@ -2298,12 +2353,14 @@ private:
SkMatrix fViewMatrixIfUsingLocalCoords;
Helper fHelper;
bool fStroked;
+ GrAA fAA;
SkSTArray<1, RRect, true> fRRects;
typedef GrMeshDrawOp INHERITED;
};
static std::unique_ptr<GrDrawOp> make_rrect_op(GrPaint&& paint,
+ GrAA aa,
const SkMatrix& viewMatrix,
const SkRRect& rrect,
const SkStrokeRec& stroke) {
@@ -2364,55 +2421,58 @@ static std::unique_ptr<GrDrawOp> make_rrect_op(GrPaint&& paint,
// if the corners are circles, use the circle renderer
if (isCircular) {
- return CircularRRectOp::Make(std::move(paint), viewMatrix, bounds, xRadius, scaledStroke.fX,
- isStrokeOnly);
+ return CircularRRectOp::Make(std::move(paint), aa, viewMatrix, bounds, xRadius,
+ scaledStroke.fX, isStrokeOnly);
// otherwise we use the ellipse renderer
} else {
- return EllipticalRRectOp::Make(std::move(paint), viewMatrix, bounds, xRadius, yRadius,
+ return EllipticalRRectOp::Make(std::move(paint), aa, viewMatrix, bounds, xRadius, yRadius,
scaledStroke, isStrokeOnly);
}
}
-std::unique_ptr<GrDrawOp> GrOvalOpFactory::MakeRRectOp(GrPaint&& paint,
- const SkMatrix& viewMatrix,
- const SkRRect& rrect,
- const SkStrokeRec& stroke,
- const GrShaderCaps* shaderCaps) {
+std::unique_ptr<GrDrawOp> GrOvalOpFactory::MakeCoverageRRectOp(GrPaint&& paint,
+ GrAA aa,
+ const SkMatrix& viewMatrix,
+ const SkRRect& rrect,
+ const SkStrokeRec& stroke,
+ const GrShaderCaps* shaderCaps) {
if (rrect.isOval()) {
- return MakeOvalOp(std::move(paint), viewMatrix, rrect.getBounds(), stroke, shaderCaps);
+ return MakeCoverageOvalOp(std::move(paint), aa, viewMatrix, rrect.getBounds(), stroke,
+ shaderCaps);
}
if (!viewMatrix.rectStaysRect() || !rrect.isSimple()) {
return nullptr;
}
- return make_rrect_op(std::move(paint), viewMatrix, rrect, stroke);
+ return make_rrect_op(std::move(paint), aa, viewMatrix, rrect, stroke);
}
///////////////////////////////////////////////////////////////////////////////
-std::unique_ptr<GrDrawOp> GrOvalOpFactory::MakeOvalOp(GrPaint&& paint,
- const SkMatrix& viewMatrix,
- const SkRect& oval,
- const SkStrokeRec& stroke,
- const GrShaderCaps* shaderCaps) {
+std::unique_ptr<GrDrawOp> GrOvalOpFactory::MakeCoverageOvalOp(GrPaint&& paint,
+ GrAA aa,
+ const SkMatrix& viewMatrix,
+ const SkRect& oval,
+ const SkStrokeRec& stroke,
+ const GrShaderCaps* shaderCaps) {
// we can draw circles
SkScalar width = oval.width();
if (width > SK_ScalarNearlyZero && SkScalarNearlyEqual(width, oval.height()) &&
circle_stays_circle(viewMatrix)) {
SkPoint center = {oval.centerX(), oval.centerY()};
- return CircleOp::Make(std::move(paint), viewMatrix, center, width / 2.f,
+ return CircleOp::Make(std::move(paint), aa, viewMatrix, center, width / 2.f,
GrStyle(stroke, nullptr));
}
// prefer the device space ellipse op for batchability
if (viewMatrix.rectStaysRect()) {
- return EllipseOp::Make(std::move(paint), viewMatrix, oval, stroke);
+ return EllipseOp::Make(std::move(paint), aa, viewMatrix, oval, stroke);
}
// Otherwise, if we have shader derivative support, render as device-independent
if (shaderCaps->shaderDerivativeSupport()) {
- return DIEllipseOp::Make(std::move(paint), viewMatrix, oval, stroke);
+ return DIEllipseOp::Make(std::move(paint), aa, viewMatrix, oval, stroke);
}
return nullptr;
@@ -2420,11 +2480,10 @@ std::unique_ptr<GrDrawOp> GrOvalOpFactory::MakeOvalOp(GrPaint&& paint,
///////////////////////////////////////////////////////////////////////////////
-std::unique_ptr<GrDrawOp> GrOvalOpFactory::MakeArcOp(GrPaint&& paint, const SkMatrix& viewMatrix,
- const SkRect& oval, SkScalar startAngle,
- SkScalar sweepAngle, bool useCenter,
- const GrStyle& style,
- const GrShaderCaps* shaderCaps) {
+std::unique_ptr<GrDrawOp> GrOvalOpFactory::MakeCoverageArcOp(
+ GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, const SkRect& oval,
+ SkScalar startAngle, SkScalar sweepAngle, bool useCenter, const GrStyle& style,
+ const GrShaderCaps* shaderCaps) {
SkASSERT(!oval.isEmpty());
SkASSERT(sweepAngle);
SkScalar width = oval.width();
@@ -2437,7 +2496,7 @@ std::unique_ptr<GrDrawOp> GrOvalOpFactory::MakeArcOp(GrPaint&& paint, const SkMa
SkPoint center = {oval.centerX(), oval.centerY()};
CircleOp::ArcParams arcParams = {SkDegreesToRadians(startAngle), SkDegreesToRadians(sweepAngle),
useCenter};
- return CircleOp::Make(std::move(paint), viewMatrix, center, width / 2.f, style, &arcParams);
+ return CircleOp::Make(std::move(paint), aa, viewMatrix, center, width / 2.f, style, &arcParams);
}
///////////////////////////////////////////////////////////////////////////////
@@ -2460,14 +2519,15 @@ GR_DRAW_OP_TEST_DEFINE(CircleOp) {
SkStrokeRec stroke = GrTest::TestStrokeRec(random);
CircleOp::ArcParams arcParamsTmp;
const CircleOp::ArcParams* arcParams = nullptr;
+ GrAA aa = random->nextBool() ? GrAA::kYes : GrAA::kNo;
if (random->nextBool()) {
arcParamsTmp.fStartAngleRadians = random->nextSScalar1() * SK_ScalarPI * 2;
arcParamsTmp.fSweepAngleRadians = random->nextSScalar1() * SK_ScalarPI * 2 - .01f;
arcParamsTmp.fUseCenter = random->nextBool();
arcParams = &arcParamsTmp;
}
- std::unique_ptr<GrDrawOp> op = CircleOp::Make(std::move(paint), viewMatrix, center, radius,
- GrStyle(stroke, nullptr), arcParams);
+ std::unique_ptr<GrDrawOp> op = CircleOp::Make(std::move(paint), aa, viewMatrix, center,
+ radius, GrStyle(stroke, nullptr), arcParams);
if (op) {
return op;
}
@@ -2477,19 +2537,24 @@ GR_DRAW_OP_TEST_DEFINE(CircleOp) {
GR_DRAW_OP_TEST_DEFINE(EllipseOp) {
SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random);
SkRect ellipse = GrTest::TestSquare(random);
- return EllipseOp::Make(std::move(paint), viewMatrix, ellipse, GrTest::TestStrokeRec(random));
+ GrAA aa = random->nextBool() ? GrAA::kYes : GrAA::kNo;
+ return EllipseOp::Make(std::move(paint), aa, viewMatrix, ellipse,
+ GrTest::TestStrokeRec(random));
}
GR_DRAW_OP_TEST_DEFINE(DIEllipseOp) {
SkMatrix viewMatrix = GrTest::TestMatrix(random);
SkRect ellipse = GrTest::TestSquare(random);
- return DIEllipseOp::Make(std::move(paint), viewMatrix, ellipse, GrTest::TestStrokeRec(random));
+ GrAA aa = random->nextBool() ? GrAA::kYes : GrAA::kNo;
+ return DIEllipseOp::Make(std::move(paint), aa, viewMatrix, ellipse,
+ GrTest::TestStrokeRec(random));
}
GR_DRAW_OP_TEST_DEFINE(RRectOp) {
SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random);
const SkRRect& rrect = GrTest::TestRRectSimple(random);
- return make_rrect_op(std::move(paint), viewMatrix, rrect, GrTest::TestStrokeRec(random));
+ GrAA aa = random->nextBool() ? GrAA::kYes : GrAA::kNo;
+ return make_rrect_op(std::move(paint), aa, viewMatrix, rrect, GrTest::TestStrokeRec(random));
}
#endif
diff --git a/src/gpu/ops/GrOvalOpFactory.h b/src/gpu/ops/GrOvalOpFactory.h
index 1bdf3ee6f6..d31e09ed9c 100644
--- a/src/gpu/ops/GrOvalOpFactory.h
+++ b/src/gpu/ops/GrOvalOpFactory.h
@@ -22,29 +22,33 @@ class SkStrokeRec;
/*
* This namespace wraps helper functions that draw ovals, rrects, and arcs (filled & stroked)
+ * The ops always use coverage even when their non-AA.
*/
class GrOvalOpFactory {
public:
- static std::unique_ptr<GrDrawOp> MakeOvalOp(GrPaint&&,
- const SkMatrix&,
- const SkRect& oval,
- const SkStrokeRec&,
- const GrShaderCaps*);
+ static std::unique_ptr<GrDrawOp> MakeCoverageOvalOp(GrPaint&&,
+ GrAA,
+ const SkMatrix&,
+ const SkRect& oval,
+ const SkStrokeRec&,
+ const GrShaderCaps*);
- static std::unique_ptr<GrDrawOp> MakeRRectOp(GrPaint&&,
- const SkMatrix&,
- const SkRRect&,
- const SkStrokeRec&,
- const GrShaderCaps*);
+ static std::unique_ptr<GrDrawOp> MakeCoverageRRectOp(GrPaint&&,
+ GrAA,
+ const SkMatrix&,
+ const SkRRect&,
+ const SkStrokeRec&,
+ const GrShaderCaps*);
- static std::unique_ptr<GrDrawOp> MakeArcOp(GrPaint&&,
- const SkMatrix&,
- const SkRect& oval,
- SkScalar startAngle,
- SkScalar sweepAngle,
- bool useCenter,
- const GrStyle&,
- const GrShaderCaps*);
+ static std::unique_ptr<GrDrawOp> MakeCoverageArcOp(GrPaint&&,
+ GrAA,
+ const SkMatrix&,
+ const SkRect& oval,
+ SkScalar startAngle,
+ SkScalar sweepAngle,
+ bool useCenter,
+ const GrStyle&,
+ const GrShaderCaps*);
};
#endif // GrOvalOpFactory_DEFINED
diff --git a/src/gpu/text/GrStencilAndCoverTextContext.cpp b/src/gpu/text/GrStencilAndCoverTextContext.cpp
index 2170f0a486..2db3f43dd6 100644
--- a/src/gpu/text/GrStencilAndCoverTextContext.cpp
+++ b/src/gpu/text/GrStencilAndCoverTextContext.cpp
@@ -580,7 +580,8 @@ void GrStencilAndCoverTextContext::TextRun::draw(GrContext* ctx,
// The run's "font" overrides the anti-aliasing of the passed in SkPaint!
GrAAType aaType = GrChooseAAType(this->aa(), renderTargetContext->fsaaType(),
- GrAllowMixedSamples::kYes, *renderTargetContext->caps());
+ GrAllowMixedSamples::kYes, GrAllowNonAABinaryCoverage::kNo,
+ nullptr, *renderTargetContext->caps());
std::unique_ptr<GrDrawOp> op = GrDrawPathRangeOp::Make(
viewMatrix, fTextRatio, fTextInverseRatio * x, fTextInverseRatio * y,