|  | /* | 
|  | * Copyright 2018 Google Inc. | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * found in the LICENSE file. | 
|  | */ | 
|  |  | 
|  | /************************************************************************************************** | 
|  | *** This file was autogenerated from GrTwoPointConicalGradientLayout.fp; do not modify. | 
|  | **************************************************************************************************/ | 
|  | #include "GrTwoPointConicalGradientLayout.h" | 
|  | #include "glsl/GrGLSLFragmentProcessor.h" | 
|  | #include "glsl/GrGLSLFragmentShaderBuilder.h" | 
|  | #include "glsl/GrGLSLProgramBuilder.h" | 
|  | #include "GrTexture.h" | 
|  | #include "SkSLCPP.h" | 
|  | #include "SkSLUtil.h" | 
|  | class GrGLSLTwoPointConicalGradientLayout : public GrGLSLFragmentProcessor { | 
|  | public: | 
|  | GrGLSLTwoPointConicalGradientLayout() {} | 
|  | void emitCode(EmitArgs& args) override { | 
|  | GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; | 
|  | const GrTwoPointConicalGradientLayout& _outer = | 
|  | args.fFp.cast<GrTwoPointConicalGradientLayout>(); | 
|  | (void)_outer; | 
|  | auto gradientMatrix = _outer.gradientMatrix(); | 
|  | (void)gradientMatrix; | 
|  | auto type = _outer.type(); | 
|  | (void)type; | 
|  | auto isRadiusIncreasing = _outer.isRadiusIncreasing(); | 
|  | (void)isRadiusIncreasing; | 
|  | auto isFocalOnCircle = _outer.isFocalOnCircle(); | 
|  | (void)isFocalOnCircle; | 
|  | auto isWellBehaved = _outer.isWellBehaved(); | 
|  | (void)isWellBehaved; | 
|  | auto isSwapped = _outer.isSwapped(); | 
|  | (void)isSwapped; | 
|  | auto isNativelyFocal = _outer.isNativelyFocal(); | 
|  | (void)isNativelyFocal; | 
|  | auto focalParams = _outer.focalParams(); | 
|  | (void)focalParams; | 
|  | fFocalParamsVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType, | 
|  | kDefault_GrSLPrecision, "focalParams"); | 
|  | SkString sk_TransformedCoords2D_0 = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]); | 
|  | fragBuilder->codeAppendf( | 
|  | "float2 p = %s;\nfloat t = -1.0;\nhalf v = 1.0;\n@switch (%d) {\n    case 1:\n     " | 
|  | "   {\n            half r0_2 = %s.y;\n            t = float(r0_2) - p.y * p.y;\n   " | 
|  | "         if (t >= 0.0) {\n                t = p.x + sqrt(t);\n            } else " | 
|  | "{\n                v = -1.0;\n            }\n        }\n        break;\n    case " | 
|  | "0:\n        {\n            half r0 = %s.x;\n            @if (%s) {\n              " | 
|  | "  t = length(p) - float(r0);\n            } else {\n                t = " | 
|  | "-length(p) - float(r0);\n       ", | 
|  | sk_TransformedCoords2D_0.c_str(), (int)_outer.type(), | 
|  | args.fUniformHandler->getUniformCStr(fFocalParamsVar), | 
|  | args.fUniformHandler->getUniformCStr(fFocalParamsVar), | 
|  | (_outer.isRadiusIncreasing() ? "true" : "false")); | 
|  | fragBuilder->codeAppendf( | 
|  | "     }\n        }\n        break;\n    case 2:\n        {\n            half invR1 " | 
|  | "= %s.x;\n            half fx = %s.y;\n            float x_t = -1.0;\n            " | 
|  | "@if (%s) {\n                x_t = dot(p, p) / p.x;\n            } else if (%s) " | 
|  | "{\n                x_t = length(p) - p.x * float(invR1);\n            } else {\n  " | 
|  | "              float temp = p.x * p.x - p.y * p.y;\n                if (temp >= " | 
|  | "0.0) {\n                    @if (%s || !%s) {\n                        x_t = " | 
|  | "-sqrt(temp) - p.x * float(invR1)", | 
|  | args.fUniformHandler->getUniformCStr(fFocalParamsVar), | 
|  | args.fUniformHandler->getUniformCStr(fFocalParamsVar), | 
|  | (_outer.isFocalOnCircle() ? "true" : "false"), | 
|  | (_outer.isWellBehaved() ? "true" : "false"), | 
|  | (_outer.isSwapped() ? "true" : "false"), | 
|  | (_outer.isRadiusIncreasing() ? "true" : "false")); | 
|  | fragBuilder->codeAppendf( | 
|  | ";\n                    } else {\n                        x_t = sqrt(temp) - p.x * " | 
|  | "float(invR1);\n                    }\n                }\n            }\n          " | 
|  | "  @if (!%s) {\n                if (x_t <= 0.0) {\n                    v = -1.0;\n " | 
|  | "               }\n            }\n            @if (%s) {\n                @if (%s) " | 
|  | "{\n                    t = x_t;\n                } else {\n                    t " | 
|  | "= x_t + float(fx);\n                }\n            } else {\n                @if " | 
|  | "(%s) {\n              ", | 
|  | (_outer.isWellBehaved() ? "true" : "false"), | 
|  | (_outer.isRadiusIncreasing() ? "true" : "false"), | 
|  | (_outer.isNativelyFocal() ? "true" : "false"), | 
|  | (_outer.isNativelyFocal() ? "true" : "false")); | 
|  | fragBuilder->codeAppendf( | 
|  | "      t = -x_t;\n                } else {\n                    t = -x_t + " | 
|  | "float(fx);\n                }\n            }\n            @if (%s) {\n            " | 
|  | "    t = 1.0 - t;\n            }\n        }\n        break;\n}\n%s = " | 
|  | "half4(half(t), v, 0.0, 0.0);\n", | 
|  | (_outer.isSwapped() ? "true" : "false"), args.fOutputColor); | 
|  | } | 
|  |  | 
|  | private: | 
|  | void onSetData(const GrGLSLProgramDataManager& pdman, | 
|  | const GrFragmentProcessor& _proc) override { | 
|  | const GrTwoPointConicalGradientLayout& _outer = | 
|  | _proc.cast<GrTwoPointConicalGradientLayout>(); | 
|  | { | 
|  | const SkPoint& focalParamsValue = _outer.focalParams(); | 
|  | if (fFocalParamsPrev != focalParamsValue) { | 
|  | fFocalParamsPrev = focalParamsValue; | 
|  | pdman.set2f(fFocalParamsVar, focalParamsValue.fX, focalParamsValue.fY); | 
|  | } | 
|  | } | 
|  | } | 
|  | SkPoint fFocalParamsPrev = SkPoint::Make(SK_FloatNaN, SK_FloatNaN); | 
|  | UniformHandle fFocalParamsVar; | 
|  | }; | 
|  | GrGLSLFragmentProcessor* GrTwoPointConicalGradientLayout::onCreateGLSLInstance() const { | 
|  | return new GrGLSLTwoPointConicalGradientLayout(); | 
|  | } | 
|  | void GrTwoPointConicalGradientLayout::onGetGLSLProcessorKey(const GrShaderCaps& caps, | 
|  | GrProcessorKeyBuilder* b) const { | 
|  | b->add32((int32_t)fType); | 
|  | b->add32((int32_t)fIsRadiusIncreasing); | 
|  | b->add32((int32_t)fIsFocalOnCircle); | 
|  | b->add32((int32_t)fIsWellBehaved); | 
|  | b->add32((int32_t)fIsSwapped); | 
|  | b->add32((int32_t)fIsNativelyFocal); | 
|  | } | 
|  | bool GrTwoPointConicalGradientLayout::onIsEqual(const GrFragmentProcessor& other) const { | 
|  | const GrTwoPointConicalGradientLayout& that = other.cast<GrTwoPointConicalGradientLayout>(); | 
|  | (void)that; | 
|  | if (fGradientMatrix != that.fGradientMatrix) return false; | 
|  | if (fType != that.fType) return false; | 
|  | if (fIsRadiusIncreasing != that.fIsRadiusIncreasing) return false; | 
|  | if (fIsFocalOnCircle != that.fIsFocalOnCircle) return false; | 
|  | if (fIsWellBehaved != that.fIsWellBehaved) return false; | 
|  | if (fIsSwapped != that.fIsSwapped) return false; | 
|  | if (fIsNativelyFocal != that.fIsNativelyFocal) return false; | 
|  | if (fFocalParams != that.fFocalParams) return false; | 
|  | return true; | 
|  | } | 
|  | GrTwoPointConicalGradientLayout::GrTwoPointConicalGradientLayout( | 
|  | const GrTwoPointConicalGradientLayout& src) | 
|  | : INHERITED(kGrTwoPointConicalGradientLayout_ClassID, src.optimizationFlags()) | 
|  | , fGradientMatrix(src.fGradientMatrix) | 
|  | , fType(src.fType) | 
|  | , fIsRadiusIncreasing(src.fIsRadiusIncreasing) | 
|  | , fIsFocalOnCircle(src.fIsFocalOnCircle) | 
|  | , fIsWellBehaved(src.fIsWellBehaved) | 
|  | , fIsSwapped(src.fIsSwapped) | 
|  | , fIsNativelyFocal(src.fIsNativelyFocal) | 
|  | , fFocalParams(src.fFocalParams) | 
|  | , fCoordTransform0(src.fCoordTransform0) { | 
|  | this->addCoordTransform(&fCoordTransform0); | 
|  | } | 
|  | std::unique_ptr<GrFragmentProcessor> GrTwoPointConicalGradientLayout::clone() const { | 
|  | return std::unique_ptr<GrFragmentProcessor>(new GrTwoPointConicalGradientLayout(*this)); | 
|  | } | 
|  | GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrTwoPointConicalGradientLayout); | 
|  | #if GR_TEST_UTILS | 
|  | std::unique_ptr<GrFragmentProcessor> GrTwoPointConicalGradientLayout::TestCreate( | 
|  | GrProcessorTestData* d) { | 
|  | SkScalar scale = GrGradientShader::RandomParams::kGradientScale; | 
|  | SkScalar offset = scale / 32.0f; | 
|  |  | 
|  | SkPoint center1 = {d->fRandom->nextRangeScalar(0.0f, scale), | 
|  | d->fRandom->nextRangeScalar(0.0f, scale)}; | 
|  | SkPoint center2 = {d->fRandom->nextRangeScalar(0.0f, scale), | 
|  | d->fRandom->nextRangeScalar(0.0f, scale)}; | 
|  | SkScalar radius1 = d->fRandom->nextRangeScalar(0.0f, scale); | 
|  | SkScalar radius2 = d->fRandom->nextRangeScalar(0.0f, scale); | 
|  |  | 
|  | constexpr int kTestTypeMask = (1 << 2) - 1, kTestNativelyFocalBit = (1 << 2), | 
|  | kTestFocalOnCircleBit = (1 << 3), kTestSwappedBit = (1 << 4); | 
|  | // We won't treat isWellDefined and isRadiusIncreasing specially because they | 
|  | // should have high probability to be turned on and off as we're getting random | 
|  | // radii and centers. | 
|  |  | 
|  | int mask = d->fRandom->nextU(); | 
|  | int type = mask & kTestTypeMask; | 
|  | if (type == static_cast<int>(Type::kRadial)) { | 
|  | center2 = center1; | 
|  | // Make sure that the radii are different | 
|  | if (SkScalarNearlyZero(radius1 - radius2)) { | 
|  | radius2 += offset; | 
|  | } | 
|  | } else if (type == static_cast<int>(Type::kStrip)) { | 
|  | radius1 = SkTMax(radius1, .1f);  // Make sure that the radius is non-zero | 
|  | radius2 = radius1; | 
|  | // Make sure that the centers are different | 
|  | if (SkScalarNearlyZero(SkPoint::Distance(center1, center2))) { | 
|  | center2.fX += offset; | 
|  | } | 
|  | } else {  // kFocal_Type | 
|  | // Make sure that the centers are different | 
|  | if (SkScalarNearlyZero(SkPoint::Distance(center1, center2))) { | 
|  | center2.fX += offset; | 
|  | } | 
|  |  | 
|  | if (kTestNativelyFocalBit & mask) { | 
|  | radius1 = 0; | 
|  | } | 
|  | if (kTestFocalOnCircleBit & mask) { | 
|  | radius2 = radius1 + SkPoint::Distance(center1, center2); | 
|  | } | 
|  | if (kTestSwappedBit & mask) { | 
|  | std::swap(radius1, radius2); | 
|  | radius2 = 0; | 
|  | } | 
|  |  | 
|  | // Make sure that the radii are different | 
|  | if (SkScalarNearlyZero(radius1 - radius2)) { | 
|  | radius2 += offset; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (SkScalarNearlyZero(radius1 - radius2) && | 
|  | SkScalarNearlyZero(SkPoint::Distance(center1, center2))) { | 
|  | radius2 += offset;  // make sure that we're not degenerated | 
|  | } | 
|  |  | 
|  | GrGradientShader::RandomParams params(d->fRandom); | 
|  | auto shader = params.fUseColors4f | 
|  | ? SkGradientShader::MakeTwoPointConical( | 
|  | center1, radius1, center2, radius2, params.fColors4f, | 
|  | params.fColorSpace, params.fStops, params.fColorCount, | 
|  | params.fTileMode) | 
|  | : SkGradientShader::MakeTwoPointConical( | 
|  | center1, radius1, center2, radius2, params.fColors, | 
|  | params.fStops, params.fColorCount, params.fTileMode); | 
|  | GrTest::TestAsFPArgs asFPArgs(d); | 
|  | std::unique_ptr<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args()); | 
|  |  | 
|  | GrAlwaysAssert(fp); | 
|  | return fp; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | // .fp files do not let you reference outside enum definitions, so we have to explicitly map | 
|  | // between the two compatible enum defs | 
|  | GrTwoPointConicalGradientLayout::Type convert_type(SkTwoPointConicalGradient::Type type) { | 
|  | switch (type) { | 
|  | case SkTwoPointConicalGradient::Type::kRadial: | 
|  | return GrTwoPointConicalGradientLayout::Type::kRadial; | 
|  | case SkTwoPointConicalGradient::Type::kStrip: | 
|  | return GrTwoPointConicalGradientLayout::Type::kStrip; | 
|  | case SkTwoPointConicalGradient::Type::kFocal: | 
|  | return GrTwoPointConicalGradientLayout::Type::kFocal; | 
|  | } | 
|  | SkDEBUGFAIL("Should not be reachable"); | 
|  | return GrTwoPointConicalGradientLayout::Type::kRadial; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<GrFragmentProcessor> GrTwoPointConicalGradientLayout::Make( | 
|  | const SkTwoPointConicalGradient& grad, const GrFPArgs& args) { | 
|  | GrTwoPointConicalGradientLayout::Type grType = convert_type(grad.getType()); | 
|  |  | 
|  | // The focalData struct is only valid if isFocal is true | 
|  | const SkTwoPointConicalGradient::FocalData& focalData = grad.getFocalData(); | 
|  | bool isFocal = grType == Type::kFocal; | 
|  |  | 
|  | // Calculate optimization switches from gradient specification | 
|  | bool isFocalOnCircle = isFocal && focalData.isFocalOnCircle(); | 
|  | bool isWellBehaved = isFocal && focalData.isWellBehaved(); | 
|  | bool isSwapped = isFocal && focalData.isSwapped(); | 
|  | bool isNativelyFocal = isFocal && focalData.isNativelyFocal(); | 
|  |  | 
|  | // Type-specific calculations: isRadiusIncreasing, focalParams, and the gradient matrix. | 
|  | // However, all types start with the total inverse local matrix calculated from the shader | 
|  | // and args | 
|  | bool isRadiusIncreasing; | 
|  | SkPoint focalParams;  // really just a 2D tuple | 
|  | SkMatrix matrix; | 
|  |  | 
|  | // Initialize the base matrix | 
|  | if (!grad.totalLocalMatrix(args.fPreLocalMatrix, args.fPostLocalMatrix)->invert(&matrix)) { | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | if (isFocal) { | 
|  | isRadiusIncreasing = (1 - focalData.fFocalX) > 0; | 
|  |  | 
|  | focalParams.set(1.0 / focalData.fR1, focalData.fFocalX); | 
|  |  | 
|  | matrix.postConcat(grad.getGradientMatrix()); | 
|  | } else if (grType == Type::kRadial) { | 
|  | SkScalar dr = grad.getDiffRadius(); | 
|  | isRadiusIncreasing = dr >= 0; | 
|  |  | 
|  | SkScalar r0 = grad.getStartRadius() / dr; | 
|  | focalParams.set(r0, r0 * r0); | 
|  |  | 
|  | // GPU radial matrix is different from the original matrix, since we map the diff radius | 
|  | // to have |dr| = 1, so manually compute the final gradient matrix here. | 
|  |  | 
|  | // Map center to (0, 0) | 
|  | matrix.postTranslate(-grad.getStartCenter().fX, -grad.getStartCenter().fY); | 
|  |  | 
|  | // scale |diffRadius| to 1 | 
|  | matrix.postScale(1 / dr, 1 / dr); | 
|  | } else {                         // kStrip | 
|  | isRadiusIncreasing = false;  // kStrip doesn't use this flag | 
|  |  | 
|  | SkScalar r0 = grad.getStartRadius() / grad.getCenterX1(); | 
|  | focalParams.set(r0, r0 * r0); | 
|  |  | 
|  | matrix.postConcat(grad.getGradientMatrix()); | 
|  | } | 
|  |  | 
|  | return std::unique_ptr<GrFragmentProcessor>(new GrTwoPointConicalGradientLayout( | 
|  | matrix, grType, isRadiusIncreasing, isFocalOnCircle, isWellBehaved, isSwapped, | 
|  | isNativelyFocal, focalParams)); | 
|  | } |