diff options
author | Chris Dalton <csmartdalton@google.com> | 2017-06-08 13:12:02 -0600 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-06-09 17:13:54 +0000 |
commit | febbffad1c24136f041d7fc2d5ffcd50e47a047f (patch) | |
tree | 860970fa626aa0901fadce958e755c107f7c97ca /src/gpu | |
parent | 01b2b83aba10bc3767d660cd619c1da58b5eb0b5 (diff) |
Improve cubic KLM accuracy
Moves cubic root finding logic out of GrPathUtils and
PathOpsCubicIntersectionTest, and unifies it in SkGeometry.
"Normalizes" the homogeneous parameter values of the roots, rather
than the cubic inflection function. Does this normalization by
twiddling the exponents instead of division (which causes a loss of
precision).
Abandons the built-in derivatives in GrCubicEffect. These don't have
high enough precision on many mobile gpus. Instead we pass the KLM
matrix to the vertex shader via uniform, where we can use it to set up
new linear functionals from which the fragment shader can calculate
the gradient of the implicit function.
Bug: skia:4410
Change-Id: Ibd64e999520adc8cdef7803a492d3699995aef5a
Reviewed-on: https://skia-review.googlesource.com/19017
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Diffstat (limited to 'src/gpu')
-rw-r--r-- | src/gpu/GrPathUtils.cpp | 142 | ||||
-rw-r--r-- | src/gpu/GrPathUtils.h | 47 | ||||
-rw-r--r-- | src/gpu/effects/GrBezierEffect.cpp | 92 | ||||
-rw-r--r-- | src/gpu/effects/GrBezierEffect.h | 31 |
4 files changed, 140 insertions, 172 deletions
diff --git a/src/gpu/GrPathUtils.cpp b/src/gpu/GrPathUtils.cpp index 91a48f7b6b..d5a237c361 100644 --- a/src/gpu/GrPathUtils.cpp +++ b/src/gpu/GrPathUtils.cpp @@ -8,7 +8,6 @@ #include "GrPathUtils.h" #include "GrTypes.h" -#include "SkGeometry.h" #include "SkMathPriv.h" static const int MAX_POINTS_PER_CURVE = 1 << 10; @@ -687,8 +686,8 @@ static void calc_loop_klm(const SkPoint pts[4], SkScalar td, SkScalar sd, SkScal SkMatrix CIT; int skipCol = calc_inverse_transpose_power_basis_matrix(pts, &CIT); - const SkScalar tesd = te * sd; const SkScalar tdse = td * se; + const SkScalar tesd = te * sd; SkMatrix klmCoeffs; int col = 0; @@ -799,108 +798,55 @@ static void calc_line_klm(const SkPoint pts[4], SkMatrix* klm) { -nx, -ny, k); } +SkCubicType GrPathUtils::getCubicKLM(const SkPoint src[4], SkMatrix* klm, SkScalar t[2], + SkScalar s[2]) { + SkScalar d[4]; + SkCubicType type = SkClassifyCubic(src, t, s, d); + switch (type) { + case SkCubicType::kSerpentine: + calc_serp_klm(src, t[0], s[0], t[1], s[1], klm); + break; + case SkCubicType::kLoop: + calc_loop_klm(src, t[0], s[0], t[1], s[1], klm); + break; + case SkCubicType::kLocalCusp: + calc_serp_klm(src, t[0], s[0], t[1], s[1], klm); + break; + case SkCubicType::kCuspAtInfinity: + calc_inf_cusp_klm(src, t[0], s[0], klm); + break; + case SkCubicType::kQuadratic: + calc_quadratic_klm(src, d[3], klm); + break; + case SkCubicType::kLineOrPoint: + calc_line_klm(src, klm); + break; + } + + return type; +} + int GrPathUtils::chopCubicAtLoopIntersection(const SkPoint src[4], SkPoint dst[10], SkMatrix* klm, int* loopIndex) { - // Variables to store the two parametric values at the loop double point. - SkScalar t1 = 0, t2 = 0; - - // Homogeneous parametric values at the loop double point. - SkScalar td, sd, te, se; - - SkScalar d[4]; - SkCubicType cType = SkClassifyCubic(src, d); - - int chop_count = 0; - if (SkCubicType::kLoop == cType) { - SkASSERT(d[0] < 0); - const SkScalar q = d[2] + SkScalarCopySign(SkScalarSqrt(-d[0]), d[2]); - td = q; - sd = 2 * d[1]; - te = 2 * (d[2] * d[2] - d[3] * d[1]); - se = d[1] * q; - - t1 = td / sd; - t2 = te / se; - // need to have t values sorted since this is what is expected by SkChopCubicAt - if (t1 > t2) { - SkTSwap(t1, t2); - } + SkSTArray<2, SkScalar> chops; + *loopIndex = -1; - SkScalar chop_ts[2]; - if (t1 > 0.f && t1 < 1.f) { - chop_ts[chop_count++] = t1; - } - if (t2 > 0.f && t2 < 1.f) { - chop_ts[chop_count++] = t2; - } - if(dst) { - SkChopCubicAt(src, dst, chop_ts, chop_count); - } - } else { - if (dst) { - memcpy(dst, src, sizeof(SkPoint) * 4); - } - } + SkScalar t[2], s[2]; + if (SkCubicType::kLoop == GrPathUtils::getCubicKLM(src, klm, t, s)) { + t[0] /= s[0]; + t[1] /= s[1]; + SkASSERT(t[0] <= t[1]); // Technically t0 != t1 in a loop, but there may be FP error. - if (loopIndex) { - if (2 == chop_count) { + if (t[0] > 0 && t[0] < 1) { + chops.push_back(t[0]); *loopIndex = 1; - } else if (1 == chop_count) { - if (t1 < 0.f) { - *loopIndex = 0; - } else { - *loopIndex = 1; - } - } else { - if (t1 < 0.f && t2 > 1.f) { - *loopIndex = 0; - } else { - *loopIndex = -1; - } + } + if (t[1] > 0 && t[1] < 1) { + chops.push_back(t[1]); + *loopIndex = chops.count() - 1; } } - if (klm) { - switch (cType) { - case SkCubicType::kSerpentine: { - SkASSERT(d[0] >= 0); - const SkScalar q = 3 * d[2] + SkScalarCopySign(SkScalarSqrt(3 * d[0]), d[2]); - const SkScalar tl = q; - const SkScalar sl = 6 * d[1]; - const SkScalar tm = 2 * d[3]; - const SkScalar sm = q; - // This copysign/abs business orients the implicit function so positive values are - // always on the "left" side of the curve. - calc_serp_klm(src, tl, sl, -SkScalarCopySign(tm, tm * sm), -SkScalarAbs(sm), klm); - break; - } - case SkCubicType::kLocalCusp: { - SkASSERT(0 == d[0]); - const SkScalar t = d[2]; - const SkScalar s = 2 * d[1]; - // This copysign/abs business orients the implicit function so positive values are - // always on the "left" side of the curve. - calc_serp_klm(src, t, s, -SkScalarCopySign(t, t * s), -SkScalarAbs(s), klm); - break; - } - case SkCubicType::kLoop: - // This copysign/abs business orients the implicit function so positive values are - // always on the "left" side of the curve. - calc_loop_klm(src, td, sd, -SkScalarCopySign(te, te * se), -SkScalarAbs(se), klm); - break; - case SkCubicType::kInfiniteCusp: { - const SkScalar tn = d[3]; - const SkScalar sn = 3 * d[2]; - calc_inf_cusp_klm(src, tn, sn, klm); - break; - } - case SkCubicType::kQuadratic: - calc_quadratic_klm(src, d[3], klm); - break; - case SkCubicType::kLineOrPoint: - calc_line_klm(src, klm); - break; - }; - } - return chop_count + 1; + SkChopCubicAt(src, dst, chops.begin(), chops.count()); + return chops.count() + 1; } diff --git a/src/gpu/GrPathUtils.h b/src/gpu/GrPathUtils.h index fdfd375427..35f94d0329 100644 --- a/src/gpu/GrPathUtils.h +++ b/src/gpu/GrPathUtils.h @@ -8,6 +8,7 @@ #ifndef GrPathUtils_DEFINED #define GrPathUtils_DEFINED +#include "SkGeometry.h" #include "SkRect.h" #include "SkPathPriv.h" #include "SkTArray.h" @@ -123,6 +124,30 @@ namespace GrPathUtils { SkPathPriv::FirstDirection dir, SkTArray<SkPoint, true>* quads); + // Computes the KLM linear functionals for the cubic implicit form. The "right" side of the + // curve (when facing in the direction of increasing parameter values) will be the area that + // satisfies: + // + // k^3 < l*m + // + // Output: + // + // klm: Holds the linear functionals K,L,M as row vectors: + // + // | ..K.. | | x | | k | + // | ..L.. | * | y | == | l | + // | ..M.. | | 1 | | m | + // + // NOTE: the KLM lines are calculated in the same space as the input control points. If you + // transform the points the lines will also need to be transformed. This can be done by mapping + // the lines with the inverse-transpose of the matrix used to map the points. + // + // t[],s[]: These are set to the two homogeneous parameter values at which points the lines L&M + // intersect with K (See SkClassifyCubic). + // + // Returns the cubic's classification. + SkCubicType getCubicKLM(const SkPoint src[4], SkMatrix* klm, SkScalar t[2], SkScalar s[2]); + // Chops the cubic bezier passed in by src, at the double point (intersection point) // if the curve is a cubic loop. If it is a loop, there will be two parametric values for // the double point: t1 and t2. We chop the cubic at these values if they are between 0 and 1. @@ -132,32 +157,20 @@ namespace GrPathUtils { // Value of 2: Only one of t1 and t2 are between (0,1), and dst will contain the two cubics, // dst[0..3] and dst[3..6] if dst is not nullptr // Value of 1: Neither t1 nor t2 are between (0,1), and dst will contain the one original cubic, - // dst[0..3] if dst is not nullptr - // - // Optional KLM Calculation: - // The function can also return the KLM linear functionals for the cubic implicit form of - // k^3 - lm. This can be shared by all chopped cubics. + // src[0..3] // // Output: // - // klm: Holds the linear functionals K,L,M as row vectors: - // - // | ..K.. | | x | | k | - // | ..L.. | * | y | == | l | - // | ..M.. | | 1 | | m | + // klm: Holds the linear functionals K,L,M as row vectors. (See getCubicKLM().) // // loopIndex: This value will tell the caller which of the chopped sections (if any) are the // actual loop. A value of -1 means there is no loop section. The caller can then use // this value to decide how/if they want to flip the orientation of this section. // The flip should be done by negating the k and l values as follows: // - // KLM.postScale(-1, -1) - // - // Notice that the KLM lines are calculated in the same space as the input control points. - // If you transform the points the lines will also need to be transformed. This can be done - // by mapping the lines with the inverse-transpose of the matrix used to map the points. - int chopCubicAtLoopIntersection(const SkPoint src[4], SkPoint dst[10] = nullptr, - SkMatrix* klm = nullptr, int* loopIndex = nullptr); + // KLM.postScale(-1, -1) + int chopCubicAtLoopIntersection(const SkPoint src[4], SkPoint dst[10], SkMatrix* klm, + int* loopIndex); // When tessellating curved paths into linear segments, this defines the maximum distance // in screen space which a segment may deviate from the mathmatically correct value. diff --git a/src/gpu/effects/GrBezierEffect.cpp b/src/gpu/effects/GrBezierEffect.cpp index 58243ea635..54a2e8576e 100644 --- a/src/gpu/effects/GrBezierEffect.cpp +++ b/src/gpu/effects/GrBezierEffect.cpp @@ -499,21 +499,31 @@ public: pdman.setMatrix3f(fViewMatrixUniform, viewMatrix); } + if (!fDevKLMMatrix.cheapEqualTo(ce.devKLMMatrix())) { + fDevKLMMatrix = ce.devKLMMatrix(); + float devKLMMatrix[3 * 3]; + GrGLSLGetMatrix<3>(devKLMMatrix, fDevKLMMatrix); + pdman.setMatrix3f(fDevKLMUniform, devKLMMatrix); + } + if (ce.color() != fColor) { float c[4]; GrColorToRGBAFloat(ce.color(), c); pdman.set4fv(fColorUniform, 1, c); fColor = ce.color(); } + this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter); } private: SkMatrix fViewMatrix; + SkMatrix fDevKLMMatrix; GrColor fColor; GrPrimitiveEdgeType fEdgeType; UniformHandle fColorUniform; UniformHandle fViewMatrixUniform; + UniformHandle fDevKLMUniform; typedef GrGLSLGeometryProcessor INHERITED; }; @@ -533,10 +543,6 @@ void GrGLCubicEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { // emit attributes varyingHandler->emitAttributes(gp); - GrGLSLVertToFrag v(kVec4f_GrSLType); - varyingHandler->addVarying("CubicCoeffs", &v, kHigh_GrSLPrecision); - vertBuilder->codeAppendf("%s = %s;", v.vsOut(), gp.inCubicCoeffs()->fName); - GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; // Setup pass through color if (!gp.colorIgnored()) { @@ -551,6 +557,30 @@ void GrGLCubicEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { gp.viewMatrix(), &fViewMatrixUniform); + // Setup KLM + const char* devkLMMatrixName; + fDevKLMUniform = uniformHandler->addUniform(kVertex_GrShaderFlag, kMat33f_GrSLType, + kHigh_GrSLPrecision, "KLM", &devkLMMatrixName); + GrGLSLVertToFrag v(kVec3f_GrSLType); + varyingHandler->addVarying("CubicCoeffs", &v, kHigh_GrSLPrecision); + vertBuilder->codeAppendf("%s = %s * vec3(%s, 1);", + v.vsOut(), devkLMMatrixName, gpArgs->fPositionVar.c_str()); + + + GrGLSLVertToFrag gradCoeffs(kVec4f_GrSLType); + if (kFillAA_GrProcessorEdgeType == fEdgeType || kHairlineAA_GrProcessorEdgeType == fEdgeType) { + varyingHandler->addVarying("GradCoeffs", &gradCoeffs, kHigh_GrSLPrecision); + vertBuilder->codeAppendf("highp float k = %s[0], l = %s[1], m = %s[2];", + v.vsOut(), v.vsOut(), v.vsOut()); + vertBuilder->codeAppendf("highp vec2 gk = vec2(%s[0][0], %s[1][0]), " + "gl = vec2(%s[0][1], %s[1][1]), " + "gm = vec2(%s[0][2], %s[1][2]);", + devkLMMatrixName, devkLMMatrixName, devkLMMatrixName, + devkLMMatrixName, devkLMMatrixName, devkLMMatrixName); + vertBuilder->codeAppendf("%s = vec4(3 * k * gk, -m * gl - l * gm);", + gradCoeffs.vsOut()); + } + // emit transforms with position this->emitTransforms(vertBuilder, varyingHandler, @@ -561,42 +591,23 @@ void GrGLCubicEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { GrShaderVar edgeAlpha("edgeAlpha", kFloat_GrSLType, 0, kHigh_GrSLPrecision); - GrShaderVar dklmdx("dklmdx", kVec3f_GrSLType, 0, kHigh_GrSLPrecision); - GrShaderVar dklmdy("dklmdy", kVec3f_GrSLType, 0, kHigh_GrSLPrecision); - GrShaderVar dfdx("dfdx", kFloat_GrSLType, 0, kHigh_GrSLPrecision); - GrShaderVar dfdy("dfdy", kFloat_GrSLType, 0, kHigh_GrSLPrecision); GrShaderVar gF("gF", kVec2f_GrSLType, 0, kHigh_GrSLPrecision); - GrShaderVar gFM("gFM", kFloat_GrSLType, 0, kHigh_GrSLPrecision); GrShaderVar func("func", kFloat_GrSLType, 0, kHigh_GrSLPrecision); fragBuilder->declAppend(edgeAlpha); - fragBuilder->declAppend(dklmdx); - fragBuilder->declAppend(dklmdy); - fragBuilder->declAppend(dfdx); - fragBuilder->declAppend(dfdy); fragBuilder->declAppend(gF); - fragBuilder->declAppend(gFM); fragBuilder->declAppend(func); switch (fEdgeType) { case kHairlineAA_GrProcessorEdgeType: { - fragBuilder->codeAppendf("%s = dFdx(%s.xyz);", dklmdx.c_str(), v.fsIn()); - fragBuilder->codeAppendf("%s = dFdy(%s.xyz);", dklmdy.c_str(), v.fsIn()); - fragBuilder->codeAppendf("%s = 3.0 * %s.x * %s.x * %s.x - %s.y * %s.z - %s.z * %s.y;", - dfdx.c_str(), v.fsIn(), v.fsIn(), dklmdx.c_str(), v.fsIn(), - dklmdx.c_str(), v.fsIn(), dklmdx.c_str()); - fragBuilder->codeAppendf("%s = 3.0 * %s.x * %s.x * %s.x - %s.y * %s.z - %s.z * %s.y;", - dfdy.c_str(), v.fsIn(), v.fsIn(), dklmdy.c_str(), v.fsIn(), - dklmdy.c_str(), v.fsIn(), dklmdy.c_str()); - fragBuilder->codeAppendf("%s = vec2(%s, %s);", gF.c_str(), dfdx.c_str(), dfdy.c_str()); - fragBuilder->codeAppendf("%s = sqrt(dot(%s, %s));", - gFM.c_str(), gF.c_str(), gF.c_str()); + fragBuilder->codeAppendf("%s = %s.x * %s.xy + %s.zw;", + gF.c_str(), v.fsIn(), gradCoeffs.fsIn(), gradCoeffs.fsIn()); fragBuilder->codeAppendf("%s = %s.x * %s.x * %s.x - %s.y * %s.z;", func.c_str(), v.fsIn(), v.fsIn(), v.fsIn(), v.fsIn(), v.fsIn()); fragBuilder->codeAppendf("%s = abs(%s);", func.c_str(), func.c_str()); - fragBuilder->codeAppendf("%s = %s / %s;", - edgeAlpha.c_str(), func.c_str(), gFM.c_str()); + fragBuilder->codeAppendf("%s = %s * inversesqrt(dot(%s, %s));", + edgeAlpha.c_str(), func.c_str(), gF.c_str(), gF.c_str()); fragBuilder->codeAppendf("%s = max(1.0 - %s, 0.0);", edgeAlpha.c_str(), edgeAlpha.c_str()); // Add line below for smooth cubic ramp @@ -606,23 +617,13 @@ void GrGLCubicEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { break; } case kFillAA_GrProcessorEdgeType: { - fragBuilder->codeAppendf("%s = dFdx(%s.xyz);", dklmdx.c_str(), v.fsIn()); - fragBuilder->codeAppendf("%s = dFdy(%s.xyz);", dklmdy.c_str(), v.fsIn()); - fragBuilder->codeAppendf("%s =" - "3.0 * %s.x * %s.x * %s.x - %s.y * %s.z - %s.z * %s.y;", - dfdx.c_str(), v.fsIn(), v.fsIn(), dklmdx.c_str(), v.fsIn(), - dklmdx.c_str(), v.fsIn(), dklmdx.c_str()); - fragBuilder->codeAppendf("%s = 3.0 * %s.x * %s.x * %s.x - %s.y * %s.z - %s.z * %s.y;", - dfdy.c_str(), v.fsIn(), v.fsIn(), dklmdy.c_str(), v.fsIn(), - dklmdy.c_str(), v.fsIn(), dklmdy.c_str()); - fragBuilder->codeAppendf("%s = vec2(%s, %s);", gF.c_str(), dfdx.c_str(), dfdy.c_str()); - fragBuilder->codeAppendf("%s = sqrt(dot(%s, %s));", - gFM.c_str(), gF.c_str(), gF.c_str()); + fragBuilder->codeAppendf("%s = %s.x * %s.xy + %s.zw;", + gF.c_str(), v.fsIn(), gradCoeffs.fsIn(), gradCoeffs.fsIn()); fragBuilder->codeAppendf("%s = %s.x * %s.x * %s.x - %s.y * %s.z;", func.c_str(), v.fsIn(), v.fsIn(), v.fsIn(), v.fsIn(), v.fsIn()); - fragBuilder->codeAppendf("%s = %s / %s;", - edgeAlpha.c_str(), func.c_str(), gFM.c_str()); + fragBuilder->codeAppendf("%s = %s * inversesqrt(dot(%s, %s));", + edgeAlpha.c_str(), func.c_str(), gF.c_str(), gF.c_str()); fragBuilder->codeAppendf("%s = clamp(0.5 - %s, 0.0, 1.0);", edgeAlpha.c_str(), edgeAlpha.c_str()); // Add line below for smooth cubic ramp @@ -667,15 +668,15 @@ GrGLSLPrimitiveProcessor* GrCubicEffect::createGLSLInstance(const GrShaderCaps&) return new GrGLCubicEffect(*this); } -GrCubicEffect::GrCubicEffect(GrColor color, const SkMatrix& viewMatrix, - GrPrimitiveEdgeType edgeType) +GrCubicEffect::GrCubicEffect(GrColor color, const SkMatrix& viewMatrix, const SkMatrix& + devKLMMatrix, GrPrimitiveEdgeType edgeType) : fColor(color) , fViewMatrix(viewMatrix) + , fDevKLMMatrix(devKLMMatrix) , fEdgeType(edgeType) { this->initClassID<GrCubicEffect>(); fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType, kHigh_GrSLPrecision); - fInCubicCoeffs = &this->addVertexAttrib("inCubicCoeffs", kVec4f_GrVertexAttribType); } ////////////////////////////////////////////////////////////////////////////// @@ -690,7 +691,8 @@ sk_sp<GrGeometryProcessor> GrCubicEffect::TestCreate(GrProcessorTestData* d) { static_cast<GrPrimitiveEdgeType>( d->fRandom->nextULessThan(kGrProcessorEdgeTypeCnt)); gp = GrCubicEffect::Make(GrRandomColor(d->fRandom), GrTest::TestMatrix(d->fRandom), - edgeType, *d->caps()); + GrTest::TestMatrix(d->fRandom), d->fRandom->nextBool(), edgeType, + *d->caps()); } while (nullptr == gp); return gp; } diff --git a/src/gpu/effects/GrBezierEffect.h b/src/gpu/effects/GrBezierEffect.h index 3a130ec187..3a97506396 100644 --- a/src/gpu/effects/GrBezierEffect.h +++ b/src/gpu/effects/GrBezierEffect.h @@ -225,24 +225,30 @@ class GrCubicEffect : public GrGeometryProcessor { public: static sk_sp<GrGeometryProcessor> Make(GrColor color, const SkMatrix& viewMatrix, + const SkMatrix& klm, + bool flipKL, const GrPrimitiveEdgeType edgeType, const GrCaps& caps) { + // Map KLM to something that operates in device space. + SkMatrix devKLM; + if (!viewMatrix.invert(&devKLM)) { + return nullptr; + } + devKLM.postConcat(klm); + if (flipKL) { + devKLM.postScale(-1, -1); + } + switch (edgeType) { case kFillAA_GrProcessorEdgeType: - if (!caps.shaderCaps()->shaderDerivativeSupport()) { - return nullptr; - } return sk_sp<GrGeometryProcessor>( - new GrCubicEffect(color, viewMatrix, kFillAA_GrProcessorEdgeType)); + new GrCubicEffect(color, viewMatrix, devKLM, kFillAA_GrProcessorEdgeType)); case kHairlineAA_GrProcessorEdgeType: - if (!caps.shaderCaps()->shaderDerivativeSupport()) { - return nullptr; - } return sk_sp<GrGeometryProcessor>( - new GrCubicEffect(color, viewMatrix, kHairlineAA_GrProcessorEdgeType)); + new GrCubicEffect(color, viewMatrix, devKLM, kHairlineAA_GrProcessorEdgeType)); case kFillBW_GrProcessorEdgeType: return sk_sp<GrGeometryProcessor>( - new GrCubicEffect(color, viewMatrix, kFillBW_GrProcessorEdgeType)); + new GrCubicEffect(color, viewMatrix, devKLM, kFillBW_GrProcessorEdgeType)); default: return nullptr; } @@ -253,26 +259,27 @@ public: const char* name() const override { return "Cubic"; } inline const Attribute* inPosition() const { return fInPosition; } - inline const Attribute* inCubicCoeffs() const { return fInCubicCoeffs; } inline bool isAntiAliased() const { return GrProcessorEdgeTypeIsAA(fEdgeType); } inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); } inline GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; } GrColor color() const { return fColor; } bool colorIgnored() const { return GrColor_ILLEGAL == fColor; } const SkMatrix& viewMatrix() const { return fViewMatrix; } + const SkMatrix& devKLMMatrix() const { return fDevKLMMatrix; } void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override; GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override; private: - GrCubicEffect(GrColor, const SkMatrix& viewMatrix, GrPrimitiveEdgeType); + GrCubicEffect(GrColor, const SkMatrix& viewMatrix, const SkMatrix& devKLMMatrix, + GrPrimitiveEdgeType); GrColor fColor; SkMatrix fViewMatrix; + SkMatrix fDevKLMMatrix; GrPrimitiveEdgeType fEdgeType; const Attribute* fInPosition; - const Attribute* fInCubicCoeffs; GR_DECLARE_GEOMETRY_PROCESSOR_TEST; |