| /* |
| * 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 "src/core/SkUtils.h" |
| #include "src/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 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( |
| &_outer, kFragment_GrShaderFlag, kHalf2_GrSLType, "focalParams"); |
| fragBuilder->codeAppendf( |
| R"SkSL(float t = -1.0; |
| half v = 1.0; |
| @switch (%d) { |
| case 1: |
| { |
| half r0_2 = %s.y; |
| t = float(r0_2) - %s.y * %s.y; |
| if (t >= 0.0) { |
| t = %s.x + sqrt(t); |
| } else { |
| v = -1.0; |
| } |
| } |
| break; |
| case 0: |
| { |
| half r0 = %s.x; |
| @if (%s) { |
| t = length(%s) - float(r0); |
| } else { |
| t = -length(%s) - float(r0); |
| } |
| } |
| break; |
| case 2: |
| { |
| half invR1 = %s.x; |
| half fx = %s.y; |
| float x_t = -1.0; |
| @if (%s) { |
| x_t = dot(%s, %s) / %s.x; |
| } else if (%s) { |
| x_t = length(%s) - %s.x * float(invR1); |
| } else { |
| float temp = %s.x * %s.x - %s.y * %s.y; |
| if (temp >= 0.0) { |
| @if (%s || !%s) { |
| x_t = -sqrt(temp) - %s.x * float(invR1); |
| } else { |
| x_t = sqrt(temp) - %s.x * float(invR1); |
| } |
| } |
| } |
| @if (!%s) { |
| if (x_t <= 0.0) { |
| v = -1.0; |
| } |
| } |
| @if (%s) { |
| @if (%s) { |
| t = x_t; |
| } else { |
| t = x_t + float(fx); |
| } |
| } else { |
| @if (%s) { |
| t = -x_t; |
| } else { |
| t = -x_t + float(fx); |
| } |
| } |
| @if (%s) { |
| t = 1.0 - t; |
| } |
| } |
| break; |
| } |
| return half4(half(t), v, 0.0, 0.0); |
| )SkSL", |
| (int)_outer.type, |
| args.fUniformHandler->getUniformCStr(focalParamsVar), |
| args.fSampleCoord, |
| args.fSampleCoord, |
| args.fSampleCoord, |
| args.fUniformHandler->getUniformCStr(focalParamsVar), |
| (_outer.isRadiusIncreasing ? "true" : "false"), |
| args.fSampleCoord, |
| args.fSampleCoord, |
| args.fUniformHandler->getUniformCStr(focalParamsVar), |
| args.fUniformHandler->getUniformCStr(focalParamsVar), |
| (_outer.isFocalOnCircle ? "true" : "false"), |
| args.fSampleCoord, |
| args.fSampleCoord, |
| args.fSampleCoord, |
| (_outer.isWellBehaved ? "true" : "false"), |
| args.fSampleCoord, |
| args.fSampleCoord, |
| args.fSampleCoord, |
| args.fSampleCoord, |
| args.fSampleCoord, |
| args.fSampleCoord, |
| (_outer.isSwapped ? "true" : "false"), |
| (_outer.isRadiusIncreasing ? "true" : "false"), |
| args.fSampleCoord, |
| args.fSampleCoord, |
| (_outer.isWellBehaved ? "true" : "false"), |
| (_outer.isRadiusIncreasing ? "true" : "false"), |
| (_outer.isNativelyFocal ? "true" : "false"), |
| (_outer.isNativelyFocal ? "true" : "false"), |
| (_outer.isSwapped ? "true" : "false")); |
| } |
| |
| private: |
| void onSetData(const GrGLSLProgramDataManager& pdman, |
| const GrFragmentProcessor& _proc) override { |
| const GrTwoPointConicalGradientLayout& _outer = |
| _proc.cast<GrTwoPointConicalGradientLayout>(); |
| { pdman.set2f(focalParamsVar, _outer.focalParams.fX, _outer.focalParams.fY); } |
| } |
| UniformHandle focalParamsVar; |
| }; |
| std::unique_ptr<GrGLSLFragmentProcessor> GrTwoPointConicalGradientLayout::onMakeProgramImpl() |
| const { |
| return std::make_unique<GrGLSLTwoPointConicalGradientLayout>(); |
| } |
| void GrTwoPointConicalGradientLayout::onGetGLSLProcessorKey(const GrShaderCaps& caps, |
| GrProcessorKeyBuilder* b) const { |
| b->addBits(2, (uint32_t)type, "type"); |
| b->addBool(isRadiusIncreasing, "isRadiusIncreasing"); |
| b->addBool(isFocalOnCircle, "isFocalOnCircle"); |
| b->addBool(isWellBehaved, "isWellBehaved"); |
| b->addBool(isSwapped, "isSwapped"); |
| b->addBool(isNativelyFocal, "isNativelyFocal"); |
| } |
| bool GrTwoPointConicalGradientLayout::onIsEqual(const GrFragmentProcessor& other) const { |
| const GrTwoPointConicalGradientLayout& that = other.cast<GrTwoPointConicalGradientLayout>(); |
| (void)that; |
| 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()) |
| , type(src.type) |
| , isRadiusIncreasing(src.isRadiusIncreasing) |
| , isFocalOnCircle(src.isFocalOnCircle) |
| , isWellBehaved(src.isWellBehaved) |
| , isSwapped(src.isSwapped) |
| , isNativelyFocal(src.isNativelyFocal) |
| , focalParams(src.focalParams) { |
| this->cloneAndRegisterAllChildProcessors(src); |
| this->setUsesSampleCoordsDirectly(); |
| } |
| std::unique_ptr<GrFragmentProcessor> GrTwoPointConicalGradientLayout::clone() const { |
| return std::make_unique<GrTwoPointConicalGradientLayout>(*this); |
| } |
| #if GR_TEST_UTILS |
| SkString GrTwoPointConicalGradientLayout::onDumpInfo() const { |
| return SkStringPrintf( |
| "(type=%d, isRadiusIncreasing=%s, isFocalOnCircle=%s, isWellBehaved=%s, isSwapped=%s, " |
| "isNativelyFocal=%s, focalParams=half2(%f, %f))", |
| (int)type, |
| (isRadiusIncreasing ? "true" : "false"), |
| (isFocalOnCircle ? "true" : "false"), |
| (isWellBehaved ? "true" : "false"), |
| (isSwapped ? "true" : "false"), |
| (isNativelyFocal ? "true" : "false"), |
| focalParams.fX, |
| focalParams.fY); |
| } |
| #endif |
| 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, center2; |
| center1.fX = d->fRandom->nextRangeScalar(0.0f, scale); |
| center1.fY = d->fRandom->nextRangeScalar(0.0f, scale); |
| center2.fX = d->fRandom->nextRangeScalar(0.0f, scale); |
| center2.fY = 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)->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 GrMatrixEffect::Make(matrix, |
| std::unique_ptr<GrFragmentProcessor>( |
| new GrTwoPointConicalGradientLayout(grType, |
| isRadiusIncreasing, |
| isFocalOnCircle, |
| isWellBehaved, |
| isSwapped, |
| isNativelyFocal, |
| focalParams))); |
| } |