| /* | |
| * 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 "include/gpu/GrTexture.h" | |
| #include "src/gpu/glsl/GrGLSLFragmentProcessor.h" | |
| #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" | |
| #include "src/gpu/glsl/GrGLSLProgramBuilder.h" | |
| #include "src/sksl/SkSLCPP.h" | |
| #include "src/sksl/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; | |
| focalParamsVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType, | |
| "focalParams"); | |
| SkString sk_TransformedCoords2D_0 = | |
| fragBuilder->ensureCoords2D(args.fTransformedCoords[0].fVaryingPoint); | |
| 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(focalParamsVar), | |
| args.fUniformHandler->getUniformCStr(focalParamsVar), | |
| (_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(focalParamsVar), | |
| args.fUniformHandler->getUniformCStr(focalParamsVar), | |
| (_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 (focalParamsPrev != focalParamsValue) { | |
| focalParamsPrev = focalParamsValue; | |
| pdman.set2f(focalParamsVar, focalParamsValue.fX, focalParamsValue.fY); | |
| } | |
| } | |
| } | |
| SkPoint focalParamsPrev = SkPoint::Make(SK_FloatNaN, SK_FloatNaN); | |
| UniformHandle focalParamsVar; | |
| }; | |
| GrGLSLFragmentProcessor* GrTwoPointConicalGradientLayout::onCreateGLSLInstance() const { | |
| return new GrGLSLTwoPointConicalGradientLayout(); | |
| } | |
| void GrTwoPointConicalGradientLayout::onGetGLSLProcessorKey(const GrShaderCaps& caps, | |
| GrProcessorKeyBuilder* b) const { | |
| b->add32((int32_t)type); | |
| b->add32((int32_t)isRadiusIncreasing); | |
| b->add32((int32_t)isFocalOnCircle); | |
| b->add32((int32_t)isWellBehaved); | |
| b->add32((int32_t)isSwapped); | |
| b->add32((int32_t)isNativelyFocal); | |
| } | |
| bool GrTwoPointConicalGradientLayout::onIsEqual(const GrFragmentProcessor& other) const { | |
| const GrTwoPointConicalGradientLayout& that = other.cast<GrTwoPointConicalGradientLayout>(); | |
| (void)that; | |
| if (gradientMatrix != that.gradientMatrix) return false; | |
| if (type != that.type) return false; | |
| if (isRadiusIncreasing != that.isRadiusIncreasing) return false; | |
| if (isFocalOnCircle != that.isFocalOnCircle) return false; | |
| if (isWellBehaved != that.isWellBehaved) return false; | |
| if (isSwapped != that.isSwapped) return false; | |
| if (isNativelyFocal != that.isNativelyFocal) return false; | |
| if (focalParams != that.focalParams) return false; | |
| return true; | |
| } | |
| GrTwoPointConicalGradientLayout::GrTwoPointConicalGradientLayout( | |
| const GrTwoPointConicalGradientLayout& src) | |
| : INHERITED(kGrTwoPointConicalGradientLayout_ClassID, src.optimizationFlags()) | |
| , fCoordTransform0(src.fCoordTransform0) | |
| , gradientMatrix(src.gradientMatrix) | |
| , type(src.type) | |
| , isRadiusIncreasing(src.isRadiusIncreasing) | |
| , isFocalOnCircle(src.isFocalOnCircle) | |
| , isWellBehaved(src.isWellBehaved) | |
| , isSwapped(src.isSwapped) | |
| , isNativelyFocal(src.isNativelyFocal) | |
| , focalParams(src.focalParams) { | |
| 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 = std::max(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()); | |
| SkASSERT_RELEASE(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)); | |
| } |