Chromium Code Reviews| Index: src/effects/gradients/SkTwoPointConicalGradient.cpp |
| diff --git a/src/effects/gradients/SkTwoPointConicalGradient.cpp b/src/effects/gradients/SkTwoPointConicalGradient.cpp |
| index 0a5e29b856a3e6c9355cf127c27297fc89e08317..28b9609e9cd7483250cc326b9bf35fabb9b6844f 100644 |
| --- a/src/effects/gradients/SkTwoPointConicalGradient.cpp |
| +++ b/src/effects/gradients/SkTwoPointConicalGradient.cpp |
| @@ -342,6 +342,14 @@ public: |
| GrGLConical2Gradient(const GrBackendEffectFactory& factory, const GrDrawEffect&); |
| virtual ~GrGLConical2Gradient() { } |
| + virtual void emitCode(GrGLFullShaderBuilder*, |
|
bsalomon
2013/10/03 14:44:52
Eek.. do we need both virtuals for emitting code o
Chris Dalton
2013/10/03 21:43:22
Done.
|
| + const GrDrawEffect&, |
| + EffectKey, |
| + const char* outputColor, |
| + const char* inputColor, |
| + const TransformedCoordsArray&, |
| + const TextureSamplerArray&) SK_OVERRIDE; |
| + |
| virtual void emitCode(GrGLShaderBuilder*, |
| const GrDrawEffect&, |
| EffectKey, |
| @@ -349,6 +357,16 @@ public: |
| const char* inputColor, |
| const TransformedCoordsArray&, |
| const TextureSamplerArray&) SK_OVERRIDE; |
| + |
| + void emitUniforms(GrGLShaderBuilder* builder, EffectKey key); |
| + |
| + void emitFragmentCode(GrGLShaderBuilder*, |
| + EffectKey, |
| + const char* outputColor, |
| + const char* inputColor, |
| + const TransformedCoordsArray&, |
| + const TextureSamplerArray&); |
| + |
| virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE; |
| static EffectKey GenKey(const GrDrawEffect&, const GrGLCaps& caps); |
| @@ -484,7 +502,7 @@ GrGLConical2Gradient::GrGLConical2Gradient(const GrBackendEffectFactory& factory |
| fIsDegenerate = data.isDegenerate(); |
| } |
| -void GrGLConical2Gradient::emitCode(GrGLShaderBuilder* builder, |
| +void GrGLConical2Gradient::emitCode(GrGLFullShaderBuilder* builder, |
| const GrDrawEffect&, |
| EffectKey key, |
| const char* outputColor, |
| @@ -492,25 +510,10 @@ void GrGLConical2Gradient::emitCode(GrGLShaderBuilder* builder, |
| const TransformedCoordsArray& coords, |
| const TextureSamplerArray& samplers) { |
| this->emitUniforms(builder, key); |
| - // 2 copies of uniform array, 1 for each of vertex & fragment shader, |
| - // to work around Xoom bug. Doesn't seem to cause performance decrease |
| - // in test apps, but need to keep an eye on it. |
| - fVSParamUni = builder->addUniformArray(GrGLShaderBuilder::kVertex_Visibility, |
| - kFloat_GrSLType, "Conical2VSParams", 6); |
| - fFSParamUni = builder->addUniformArray(GrGLShaderBuilder::kFragment_Visibility, |
| - kFloat_GrSLType, "Conical2FSParams", 6); |
| - // For radial gradients without perspective we can pass the linear |
| - // part of the quadratic as a varying. |
| - GrGLShaderBuilder::VertexBuilder* vertexBuilder = |
| - (kVec2f_GrSLType == coords[0].type()) ? builder->getVertexBuilder() : NULL; |
| - if (NULL != vertexBuilder) { |
| - vertexBuilder->addVarying(kFloat_GrSLType, "Conical2BCoeff", |
| - &fVSVaryingName, &fFSVaryingName); |
| - } |
| - |
| - // VS |
| - { |
| + if (kVec2f_GrSLType == coords[0].type()) { |
| + // For conical gradients without perspective we can pass the linear |
| + // part of the quadratic as a varying. |
| SkString p2; // distance between centers |
| SkString p3; // start radius |
| SkString p5; // difference in radii (r1 - r0) |
| @@ -518,134 +521,160 @@ void GrGLConical2Gradient::emitCode(GrGLShaderBuilder* builder, |
| builder->getUniformVariable(fVSParamUni).appendArrayAccess(3, &p3); |
| builder->getUniformVariable(fVSParamUni).appendArrayAccess(5, &p5); |
| - // For radial gradients without perspective we can pass the linear |
| - // part of the quadratic as a varying. |
| - if (NULL != vertexBuilder) { |
| - // r2Var = -2 * (r2Parm[2] * varCoord.x - r2Param[3] * r2Param[5]) |
| - vertexBuilder->vsCodeAppendf("\t%s = -2.0 * (%s * %s.x + %s * %s);\n", |
| - fVSVaryingName, p2.c_str(), |
| - coords[0].getVSName().c_str(), p3.c_str(), p5.c_str()); |
| - } |
| + builder->addVarying(kFloat_GrSLType, "Conical2BCoeff", &fVSVaryingName, &fFSVaryingName); |
| + |
| + // r2Var = -2 * (r2Parm[2] * varCoord.x - r2Param[3] * r2Param[5]) |
| + builder->vsCodeAppendf("\t%s = -2.0 * (%s * %s.x + %s * %s);\n", |
| + fVSVaryingName, p2.c_str(), |
| + coords[0].getVSName().c_str(), p3.c_str(), p5.c_str()); |
| } |
| - // FS |
| - { |
| - SkString coords2D = builder->ensureFSCoords2D(coords, 0); |
| - SkString cName("c"); |
| - SkString ac4Name("ac4"); |
| - SkString dName("d"); |
| - SkString qName("q"); |
| - SkString r0Name("r0"); |
| - SkString r1Name("r1"); |
| - SkString tName("t"); |
| - SkString p0; // 4a |
| - SkString p1; // 1/a |
| - SkString p2; // distance between centers |
| - SkString p3; // start radius |
| - SkString p4; // start radius squared |
| - SkString p5; // difference in radii (r1 - r0) |
| + this->emitFragmentCode(builder, key, outputColor, inputColor, coords, samplers); |
| +} |
| - builder->getUniformVariable(fFSParamUni).appendArrayAccess(0, &p0); |
| - builder->getUniformVariable(fFSParamUni).appendArrayAccess(1, &p1); |
| - builder->getUniformVariable(fFSParamUni).appendArrayAccess(2, &p2); |
| - builder->getUniformVariable(fFSParamUni).appendArrayAccess(3, &p3); |
| - builder->getUniformVariable(fFSParamUni).appendArrayAccess(4, &p4); |
| - builder->getUniformVariable(fFSParamUni).appendArrayAccess(5, &p5); |
| - |
| - // If we we're able to interpolate the linear component, |
| - // bVar is the varying; otherwise compute it |
| - SkString bVar; |
| - if (NULL != vertexBuilder) { |
| - bVar = fFSVaryingName; |
| - } else { |
| - bVar = "b"; |
| - builder->fsCodeAppendf("\tfloat %s = -2.0 * (%s * %s.x + %s * %s);\n", |
| - bVar.c_str(), p2.c_str(), coords2D.c_str(), |
| - p3.c_str(), p5.c_str()); |
| - } |
| +void GrGLConical2Gradient::emitCode(GrGLShaderBuilder* builder, |
| + const GrDrawEffect&, |
| + EffectKey key, |
| + const char* outputColor, |
| + const char* inputColor, |
| + const TransformedCoordsArray& coords, |
| + const TextureSamplerArray& samplers) { |
| + this->emitUniforms(builder, key); |
| + this->emitFragmentCode(builder, key, outputColor, inputColor, coords, samplers); |
| +} |
| - // output will default to transparent black (we simply won't write anything |
| - // else to it if invalid, instead of discarding or returning prematurely) |
| - builder->fsCodeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", outputColor); |
| - |
| - // c = (x^2)+(y^2) - params[4] |
| - builder->fsCodeAppendf("\tfloat %s = dot(%s, %s) - %s;\n", cName.c_str(), |
| - coords2D.c_str(), coords2D.c_str(), |
| - p4.c_str()); |
| - |
| - // Non-degenerate case (quadratic) |
| - if (!fIsDegenerate) { |
| - |
| - // ac4 = params[0] * c |
| - builder->fsCodeAppendf("\tfloat %s = %s * %s;\n", ac4Name.c_str(), p0.c_str(), |
| - cName.c_str()); |
| - |
| - // d = b^2 - ac4 |
| - builder->fsCodeAppendf("\tfloat %s = %s * %s - %s;\n", dName.c_str(), |
| - bVar.c_str(), bVar.c_str(), ac4Name.c_str()); |
| - |
| - // only proceed if discriminant is >= 0 |
| - builder->fsCodeAppendf("\tif (%s >= 0.0) {\n", dName.c_str()); |
| - |
| - // intermediate value we'll use to compute the roots |
| - // q = -0.5 * (b +/- sqrt(d)) |
| - builder->fsCodeAppendf("\t\tfloat %s = -0.5 * (%s + (%s < 0.0 ? -1.0 : 1.0)" |
| - " * sqrt(%s));\n", qName.c_str(), bVar.c_str(), |
| - bVar.c_str(), dName.c_str()); |
| - |
| - // compute both roots |
| - // r0 = q * params[1] |
| - builder->fsCodeAppendf("\t\tfloat %s = %s * %s;\n", r0Name.c_str(), |
| - qName.c_str(), p1.c_str()); |
| - // r1 = c / q |
| - builder->fsCodeAppendf("\t\tfloat %s = %s / %s;\n", r1Name.c_str(), |
| - cName.c_str(), qName.c_str()); |
| - |
| - // Note: If there are two roots that both generate radius(t) > 0, the |
| - // Canvas spec says to choose the larger t. |
| - |
| - // so we'll look at the larger one first: |
| - builder->fsCodeAppendf("\t\tfloat %s = max(%s, %s);\n", tName.c_str(), |
| - r0Name.c_str(), r1Name.c_str()); |
| - |
| - // if r(t) > 0, then we're done; t will be our x coordinate |
| - builder->fsCodeAppendf("\t\tif (%s * %s + %s > 0.0) {\n", tName.c_str(), |
| - p5.c_str(), p3.c_str()); |
| - |
| - builder->fsCodeAppend("\t\t"); |
| - this->emitColor(builder, tName.c_str(), key, outputColor, inputColor, samplers); |
| - |
| - // otherwise, if r(t) for the larger root was <= 0, try the other root |
| - builder->fsCodeAppend("\t\t} else {\n"); |
| - builder->fsCodeAppendf("\t\t\t%s = min(%s, %s);\n", tName.c_str(), |
| - r0Name.c_str(), r1Name.c_str()); |
| - |
| - // if r(t) > 0 for the smaller root, then t will be our x coordinate |
| - builder->fsCodeAppendf("\t\t\tif (%s * %s + %s > 0.0) {\n", |
| - tName.c_str(), p5.c_str(), p3.c_str()); |
| - |
| - builder->fsCodeAppend("\t\t\t"); |
| - this->emitColor(builder, tName.c_str(), key, outputColor, inputColor, samplers); |
| - |
| - // end if (r(t) > 0) for smaller root |
| - builder->fsCodeAppend("\t\t\t}\n"); |
| - // end if (r(t) > 0), else, for larger root |
| - builder->fsCodeAppend("\t\t}\n"); |
| - // end if (discriminant >= 0) |
| - builder->fsCodeAppend("\t}\n"); |
| - } else { |
| +void GrGLConical2Gradient::emitUniforms(GrGLShaderBuilder* builder, EffectKey key) { |
| + this->INHERITED::emitUniforms(builder, key); |
| + // 2 copies of uniform array, 1 for each of vertex & fragment shader, |
| + // to work around Xoom bug. Doesn't seem to cause performance decrease |
| + // in test apps, but need to keep an eye on it. |
| + fVSParamUni = builder->addUniformArray(GrGLShaderBuilder::kVertex_Visibility, |
| + kFloat_GrSLType, "Conical2VSParams", 6); |
| + fFSParamUni = builder->addUniformArray(GrGLShaderBuilder::kFragment_Visibility, |
| + kFloat_GrSLType, "Conical2FSParams", 6); |
| +} |
| - // linear case: t = -c/b |
| - builder->fsCodeAppendf("\tfloat %s = -(%s / %s);\n", tName.c_str(), |
| - cName.c_str(), bVar.c_str()); |
| +void GrGLConical2Gradient::emitFragmentCode(GrGLShaderBuilder* builder, |
| + EffectKey key, |
| + const char* outputColor, |
| + const char* inputColor, |
| + const TransformedCoordsArray& coords, |
| + const TextureSamplerArray& samplers) { |
| + SkString coords2D = builder->ensureFSCoords2D(coords, 0); |
| + SkString cName("c"); |
| + SkString ac4Name("ac4"); |
| + SkString dName("d"); |
| + SkString qName("q"); |
| + SkString r0Name("r0"); |
| + SkString r1Name("r1"); |
| + SkString tName("t"); |
| + SkString p0; // 4a |
| + SkString p1; // 1/a |
| + SkString p2; // distance between centers |
| + SkString p3; // start radius |
| + SkString p4; // start radius squared |
| + SkString p5; // difference in radii (r1 - r0) |
| + |
| + builder->getUniformVariable(fFSParamUni).appendArrayAccess(0, &p0); |
| + builder->getUniformVariable(fFSParamUni).appendArrayAccess(1, &p1); |
| + builder->getUniformVariable(fFSParamUni).appendArrayAccess(2, &p2); |
| + builder->getUniformVariable(fFSParamUni).appendArrayAccess(3, &p3); |
| + builder->getUniformVariable(fFSParamUni).appendArrayAccess(4, &p4); |
| + builder->getUniformVariable(fFSParamUni).appendArrayAccess(5, &p5); |
| + |
| + // If we we're able to interpolate the linear component, |
| + // bVar is the varying; otherwise compute it |
| + SkString bVar; |
| + if (NULL != fFSVaryingName) { |
| + bVar = fFSVaryingName; |
| + } else { |
| + bVar = "b"; |
| + builder->fsCodeAppendf("\tfloat %s = -2.0 * (%s * %s.x + %s * %s);\n", |
| + bVar.c_str(), p2.c_str(), coords2D.c_str(), |
| + p3.c_str(), p5.c_str()); |
| + } |
| - // if r(t) > 0, then t will be the x coordinate |
| - builder->fsCodeAppendf("\tif (%s * %s + %s > 0.0) {\n", tName.c_str(), |
| - p5.c_str(), p3.c_str()); |
| - builder->fsCodeAppend("\t"); |
| - this->emitColor(builder, tName.c_str(), key, outputColor, inputColor, samplers); |
| - builder->fsCodeAppend("\t}\n"); |
| - } |
| + // output will default to transparent black (we simply won't write anything |
| + // else to it if invalid, instead of discarding or returning prematurely) |
| + builder->fsCodeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", outputColor); |
| + |
| + // c = (x^2)+(y^2) - params[4] |
| + builder->fsCodeAppendf("\tfloat %s = dot(%s, %s) - %s;\n", cName.c_str(), |
| + coords2D.c_str(), coords2D.c_str(), |
| + p4.c_str()); |
| + |
| + // Non-degenerate case (quadratic) |
| + if (!fIsDegenerate) { |
| + |
| + // ac4 = params[0] * c |
| + builder->fsCodeAppendf("\tfloat %s = %s * %s;\n", ac4Name.c_str(), p0.c_str(), |
| + cName.c_str()); |
| + |
| + // d = b^2 - ac4 |
| + builder->fsCodeAppendf("\tfloat %s = %s * %s - %s;\n", dName.c_str(), |
| + bVar.c_str(), bVar.c_str(), ac4Name.c_str()); |
| + |
| + // only proceed if discriminant is >= 0 |
| + builder->fsCodeAppendf("\tif (%s >= 0.0) {\n", dName.c_str()); |
| + |
| + // intermediate value we'll use to compute the roots |
| + // q = -0.5 * (b +/- sqrt(d)) |
| + builder->fsCodeAppendf("\t\tfloat %s = -0.5 * (%s + (%s < 0.0 ? -1.0 : 1.0)" |
| + " * sqrt(%s));\n", qName.c_str(), bVar.c_str(), |
| + bVar.c_str(), dName.c_str()); |
| + |
| + // compute both roots |
| + // r0 = q * params[1] |
| + builder->fsCodeAppendf("\t\tfloat %s = %s * %s;\n", r0Name.c_str(), |
| + qName.c_str(), p1.c_str()); |
| + // r1 = c / q |
| + builder->fsCodeAppendf("\t\tfloat %s = %s / %s;\n", r1Name.c_str(), |
| + cName.c_str(), qName.c_str()); |
| + |
| + // Note: If there are two roots that both generate radius(t) > 0, the |
| + // Canvas spec says to choose the larger t. |
| + |
| + // so we'll look at the larger one first: |
| + builder->fsCodeAppendf("\t\tfloat %s = max(%s, %s);\n", tName.c_str(), |
| + r0Name.c_str(), r1Name.c_str()); |
| + |
| + // if r(t) > 0, then we're done; t will be our x coordinate |
| + builder->fsCodeAppendf("\t\tif (%s * %s + %s > 0.0) {\n", tName.c_str(), |
| + p5.c_str(), p3.c_str()); |
| + |
| + builder->fsCodeAppend("\t\t"); |
| + this->emitColor(builder, tName.c_str(), key, outputColor, inputColor, samplers); |
| + |
| + // otherwise, if r(t) for the larger root was <= 0, try the other root |
| + builder->fsCodeAppend("\t\t} else {\n"); |
| + builder->fsCodeAppendf("\t\t\t%s = min(%s, %s);\n", tName.c_str(), |
| + r0Name.c_str(), r1Name.c_str()); |
| + |
| + // if r(t) > 0 for the smaller root, then t will be our x coordinate |
| + builder->fsCodeAppendf("\t\t\tif (%s * %s + %s > 0.0) {\n", |
| + tName.c_str(), p5.c_str(), p3.c_str()); |
| + |
| + builder->fsCodeAppend("\t\t\t"); |
| + this->emitColor(builder, tName.c_str(), key, outputColor, inputColor, samplers); |
| + |
| + // end if (r(t) > 0) for smaller root |
| + builder->fsCodeAppend("\t\t\t}\n"); |
| + // end if (r(t) > 0), else, for larger root |
| + builder->fsCodeAppend("\t\t}\n"); |
| + // end if (discriminant >= 0) |
| + builder->fsCodeAppend("\t}\n"); |
| + } else { |
| + |
| + // linear case: t = -c/b |
| + builder->fsCodeAppendf("\tfloat %s = -(%s / %s);\n", tName.c_str(), |
| + cName.c_str(), bVar.c_str()); |
| + |
| + // if r(t) > 0, then t will be the x coordinate |
| + builder->fsCodeAppendf("\tif (%s * %s + %s > 0.0) {\n", tName.c_str(), |
| + p5.c_str(), p3.c_str()); |
| + builder->fsCodeAppend("\t"); |
| + this->emitColor(builder, tName.c_str(), key, outputColor, inputColor, samplers); |
| + builder->fsCodeAppend("\t}\n"); |
| } |
| } |