| /* |
| * 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 ", |
| _outer.computeLocalCoordsInVertexShader() ? sk_TransformedCoords2D_0.c_str() |
| : "_coords", |
| (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 = 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)); |
| } |