LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/effects/gradients - SkRadialGradient.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 198 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 33 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2012 Google Inc.
       3             :  *
       4             :  * Use of this source code is governed by a BSD-style license that can be
       5             :  * found in the LICENSE file.
       6             :  */
       7             : 
       8             : #include "SkRadialGradient.h"
       9             : #include "SkNx.h"
      10             : 
      11             : namespace {
      12             : 
      13             : // GCC doesn't like using static functions as template arguments.  So force these to be non-static.
      14           0 : inline SkFixed mirror_tileproc_nonstatic(SkFixed x) {
      15           0 :     return mirror_tileproc(x);
      16             : }
      17             : 
      18           0 : inline SkFixed repeat_tileproc_nonstatic(SkFixed x) {
      19           0 :     return repeat_tileproc(x);
      20             : }
      21             : 
      22           0 : SkMatrix rad_to_unit_matrix(const SkPoint& center, SkScalar radius) {
      23           0 :     SkScalar    inv = SkScalarInvert(radius);
      24             : 
      25             :     SkMatrix matrix;
      26           0 :     matrix.setTranslate(-center.fX, -center.fY);
      27           0 :     matrix.postScale(inv, inv);
      28           0 :     return matrix;
      29             : }
      30             : 
      31             : 
      32             : }  // namespace
      33             : 
      34             : /////////////////////////////////////////////////////////////////////
      35             : 
      36           0 : SkRadialGradient::SkRadialGradient(const SkPoint& center, SkScalar radius, const Descriptor& desc)
      37           0 :     : SkGradientShaderBase(desc, rad_to_unit_matrix(center, radius))
      38             :     , fCenter(center)
      39           0 :     , fRadius(radius) {
      40           0 : }
      41             : 
      42           0 : SkShader::Context* SkRadialGradient::onMakeContext(
      43             :     const ContextRec& rec, SkArenaAlloc* alloc) const
      44             : {
      45           0 :     return CheckedMakeContext<RadialGradientContext>(alloc, *this, rec);
      46             : }
      47             : 
      48           0 : SkRadialGradient::RadialGradientContext::RadialGradientContext(
      49           0 :         const SkRadialGradient& shader, const ContextRec& rec)
      50           0 :     : INHERITED(shader, rec) {}
      51             : 
      52           0 : SkShader::GradientType SkRadialGradient::asAGradient(GradientInfo* info) const {
      53           0 :     if (info) {
      54           0 :         commonAsAGradient(info);
      55           0 :         info->fPoint[0] = fCenter;
      56           0 :         info->fRadius[0] = fRadius;
      57             :     }
      58           0 :     return kRadial_GradientType;
      59             : }
      60             : 
      61           0 : sk_sp<SkFlattenable> SkRadialGradient::CreateProc(SkReadBuffer& buffer) {
      62           0 :     DescriptorScope desc;
      63           0 :     if (!desc.unflatten(buffer)) {
      64           0 :         return nullptr;
      65             :     }
      66           0 :     const SkPoint center = buffer.readPoint();
      67           0 :     const SkScalar radius = buffer.readScalar();
      68           0 :     return SkGradientShader::MakeRadial(center, radius, desc.fColors, std::move(desc.fColorSpace),
      69             :                                         desc.fPos, desc.fCount, desc.fTileMode, desc.fGradFlags,
      70           0 :                                         desc.fLocalMatrix);
      71             : }
      72             : 
      73           0 : void SkRadialGradient::flatten(SkWriteBuffer& buffer) const {
      74           0 :     this->INHERITED::flatten(buffer);
      75           0 :     buffer.writePoint(fCenter);
      76           0 :     buffer.writeScalar(fRadius);
      77           0 : }
      78             : 
      79             : namespace {
      80             : 
      81           0 : inline bool radial_completely_pinned(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy) {
      82             :     // fast, overly-conservative test: checks unit square instead of unit circle
      83           0 :     bool xClamped = (fx >= 1 && dx >= 0) || (fx <= -1 && dx <= 0);
      84           0 :     bool yClamped = (fy >= 1 && dy >= 0) || (fy <= -1 && dy <= 0);
      85           0 :     return xClamped || yClamped;
      86             : }
      87             : 
      88             : typedef void (* RadialShadeProc)(SkScalar sfx, SkScalar sdx,
      89             :         SkScalar sfy, SkScalar sdy,
      90             :         SkPMColor* dstC, const SkPMColor* cache,
      91             :         int count, int toggle);
      92             : 
      93           0 : static inline Sk4f fast_sqrt(const Sk4f& R) {
      94           0 :     return R * R.rsqrt();
      95             : }
      96             : 
      97           0 : static inline Sk4f sum_squares(const Sk4f& a, const Sk4f& b) {
      98           0 :     return a * a + b * b;
      99             : }
     100             : 
     101           0 : void shadeSpan_radial_clamp2(SkScalar sfx, SkScalar sdx, SkScalar sfy, SkScalar sdy,
     102             :                              SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
     103             :                              int count, int toggle) {
     104           0 :     if (radial_completely_pinned(sfx, sdx, sfy, sdy)) {
     105           0 :         unsigned fi = SkGradientShaderBase::kCache32Count - 1;
     106           0 :         sk_memset32_dither(dstC,
     107           0 :                            cache[toggle + fi],
     108           0 :                            cache[next_dither_toggle(toggle) + fi],
     109           0 :                            count);
     110             :     } else {
     111             :         const Sk4f min(SK_ScalarNearlyZero);
     112             :         const Sk4f max(255);
     113           0 :         const float scale = 255;
     114           0 :         sfx *= scale;
     115           0 :         sfy *= scale;
     116           0 :         sdx *= scale;
     117           0 :         sdy *= scale;
     118           0 :         const Sk4f fx4(sfx, sfx + sdx, sfx + 2*sdx, sfx + 3*sdx);
     119           0 :         const Sk4f fy4(sfy, sfy + sdy, sfy + 2*sdy, sfy + 3*sdy);
     120           0 :         const Sk4f dx4(sdx * 4);
     121           0 :         const Sk4f dy4(sdy * 4);
     122             : 
     123           0 :         Sk4f tmpxy = fx4 * dx4 + fy4 * dy4;
     124           0 :         Sk4f tmpdxdy = sum_squares(dx4, dy4);
     125           0 :         Sk4f R = Sk4f::Max(sum_squares(fx4, fy4), min);
     126           0 :         Sk4f dR = tmpxy + tmpxy + tmpdxdy;
     127           0 :         const Sk4f ddR = tmpdxdy + tmpdxdy;
     128             : 
     129           0 :         for (int i = 0; i < (count >> 2); ++i) {
     130           0 :             Sk4f dist = Sk4f::Min(fast_sqrt(R), max);
     131           0 :             R = Sk4f::Max(R + dR, min);
     132           0 :             dR = dR + ddR;
     133             : 
     134             :             uint8_t fi[4];
     135           0 :             SkNx_cast<uint8_t>(dist).store(fi);
     136             : 
     137           0 :             for (int i = 0; i < 4; i++) {
     138           0 :                 *dstC++ = cache[toggle + fi[i]];
     139           0 :                 toggle = next_dither_toggle(toggle);
     140             :             }
     141             :         }
     142           0 :         count &= 3;
     143           0 :         if (count) {
     144           0 :             Sk4f dist = Sk4f::Min(fast_sqrt(R), max);
     145             : 
     146             :             uint8_t fi[4];
     147           0 :             SkNx_cast<uint8_t>(dist).store(fi);
     148           0 :             for (int i = 0; i < count; i++) {
     149           0 :                 *dstC++ = cache[toggle + fi[i]];
     150           0 :                 toggle = next_dither_toggle(toggle);
     151             :             }
     152             :         }
     153             :     }
     154           0 : }
     155             : 
     156             : // Unrolling this loop doesn't seem to help (when float); we're stalling to
     157             : // get the results of the sqrt (?), and don't have enough extra registers to
     158             : // have many in flight.
     159             : template <SkFixed (*TileProc)(SkFixed)>
     160           0 : void shadeSpan_radial(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy,
     161             :                       SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
     162             :                       int count, int toggle) {
     163           0 :     do {
     164           0 :         const SkFixed dist = SkFloatToFixed(sk_float_sqrt(fx*fx + fy*fy));
     165           0 :         const unsigned fi = TileProc(dist);
     166           0 :         SkASSERT(fi <= 0xFFFF);
     167           0 :         *dstC++ = cache[toggle + (fi >> SkGradientShaderBase::kCache32Shift)];
     168           0 :         toggle = next_dither_toggle(toggle);
     169           0 :         fx += dx;
     170           0 :         fy += dy;
     171             :     } while (--count != 0);
     172           0 : }
     173             : 
     174           0 : void shadeSpan_radial_mirror(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy,
     175             :                              SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
     176             :                              int count, int toggle) {
     177           0 :     shadeSpan_radial<mirror_tileproc_nonstatic>(fx, dx, fy, dy, dstC, cache, count, toggle);
     178           0 : }
     179             : 
     180           0 : void shadeSpan_radial_repeat(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy,
     181             :                              SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
     182             :                              int count, int toggle) {
     183           0 :     shadeSpan_radial<repeat_tileproc_nonstatic>(fx, dx, fy, dy, dstC, cache, count, toggle);
     184           0 : }
     185             : 
     186             : }  // namespace
     187             : 
     188           0 : void SkRadialGradient::RadialGradientContext::shadeSpan(int x, int y,
     189             :                                                         SkPMColor* SK_RESTRICT dstC, int count) {
     190           0 :     SkASSERT(count > 0);
     191             : 
     192           0 :     const SkRadialGradient& radialGradient = static_cast<const SkRadialGradient&>(fShader);
     193             : 
     194             :     SkPoint             srcPt;
     195           0 :     SkMatrix::MapXYProc dstProc = fDstToIndexProc;
     196           0 :     TileProc            proc = radialGradient.fTileProc;
     197           0 :     const SkPMColor* SK_RESTRICT cache = fCache->getCache32();
     198           0 :     int toggle = init_dither_toggle(x, y);
     199             : 
     200           0 :     if (fDstToIndexClass != kPerspective_MatrixClass) {
     201           0 :         dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
     202           0 :                              SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
     203           0 :         SkScalar sdx = fDstToIndex.getScaleX();
     204           0 :         SkScalar sdy = fDstToIndex.getSkewY();
     205             : 
     206           0 :         if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
     207           0 :             const auto step = fDstToIndex.fixedStepInX(SkIntToScalar(y));
     208           0 :             sdx = step.fX;
     209           0 :             sdy = step.fY;
     210             :         } else {
     211           0 :             SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
     212             :         }
     213             : 
     214           0 :         RadialShadeProc shadeProc = shadeSpan_radial_repeat;
     215           0 :         if (SkShader::kClamp_TileMode == radialGradient.fTileMode) {
     216           0 :             shadeProc = shadeSpan_radial_clamp2;
     217           0 :         } else if (SkShader::kMirror_TileMode == radialGradient.fTileMode) {
     218           0 :             shadeProc = shadeSpan_radial_mirror;
     219             :         } else {
     220           0 :             SkASSERT(SkShader::kRepeat_TileMode == radialGradient.fTileMode);
     221             :         }
     222           0 :         (*shadeProc)(srcPt.fX, sdx, srcPt.fY, sdy, dstC, cache, count, toggle);
     223             :     } else {    // perspective case
     224           0 :         SkScalar dstX = SkIntToScalar(x);
     225           0 :         SkScalar dstY = SkIntToScalar(y);
     226           0 :         do {
     227           0 :             dstProc(fDstToIndex, dstX, dstY, &srcPt);
     228           0 :             unsigned fi = proc(SkScalarToFixed(srcPt.length()));
     229           0 :             SkASSERT(fi <= 0xFFFF);
     230           0 :             *dstC++ = cache[fi >> SkGradientShaderBase::kCache32Shift];
     231           0 :             dstX += SK_Scalar1;
     232             :         } while (--count != 0);
     233             :     }
     234           0 : }
     235             : 
     236             : /////////////////////////////////////////////////////////////////////
     237             : 
     238             : #if SK_SUPPORT_GPU
     239             : 
     240             : #include "SkGr.h"
     241             : #include "GrShaderCaps.h"
     242             : #include "glsl/GrGLSLFragmentShaderBuilder.h"
     243             : 
     244             : class GrRadialGradient : public GrGradientEffect {
     245             : public:
     246             :     class GLSLRadialProcessor;
     247             : 
     248           0 :     static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args) {
     249           0 :         return sk_sp<GrFragmentProcessor>(new GrRadialGradient(args));
     250             :     }
     251             : 
     252           0 :     ~GrRadialGradient() override {}
     253             : 
     254           0 :     const char* name() const override { return "Radial Gradient"; }
     255             : 
     256             : private:
     257           0 :     GrRadialGradient(const CreateArgs& args) : INHERITED(args, args.fShader->colorsAreOpaque()) {
     258           0 :         this->initClassID<GrRadialGradient>();
     259           0 :     }
     260             : 
     261             :     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
     262             : 
     263             :     virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
     264             :                                        GrProcessorKeyBuilder* b) const override;
     265             : 
     266             :     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
     267             : 
     268             :     typedef GrGradientEffect INHERITED;
     269             : };
     270             : 
     271             : /////////////////////////////////////////////////////////////////////
     272             : 
     273             : class GrRadialGradient::GLSLRadialProcessor : public GrGradientEffect::GLSLProcessor {
     274             : public:
     275           0 :     GLSLRadialProcessor(const GrProcessor&) {}
     276           0 :     ~GLSLRadialProcessor() override {}
     277             : 
     278             :     virtual void emitCode(EmitArgs&) override;
     279             : 
     280           0 :     static void GenKey(const GrProcessor& processor, const GrShaderCaps&, GrProcessorKeyBuilder* b) {
     281           0 :         b->add32(GenBaseGradientKey(processor));
     282           0 :     }
     283             : 
     284             : private:
     285             :     typedef GrGradientEffect::GLSLProcessor INHERITED;
     286             : 
     287             : };
     288             : 
     289             : /////////////////////////////////////////////////////////////////////
     290             : 
     291           0 : GrGLSLFragmentProcessor* GrRadialGradient::onCreateGLSLInstance() const {
     292           0 :     return new GrRadialGradient::GLSLRadialProcessor(*this);
     293             : }
     294             : 
     295           0 : void GrRadialGradient::onGetGLSLProcessorKey(const GrShaderCaps& caps,
     296             :                                              GrProcessorKeyBuilder* b) const {
     297           0 :     GrRadialGradient::GLSLRadialProcessor::GenKey(*this, caps, b);
     298           0 : }
     299             : 
     300             : /////////////////////////////////////////////////////////////////////
     301             : 
     302             : GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRadialGradient);
     303             : 
     304             : #if GR_TEST_UTILS
     305           0 : sk_sp<GrFragmentProcessor> GrRadialGradient::TestCreate(GrProcessorTestData* d) {
     306           0 :     sk_sp<SkShader> shader;
     307           0 :     do {
     308           0 :         RandomGradientParams params(d->fRandom);
     309           0 :         SkPoint center = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
     310           0 :         SkScalar radius = d->fRandom->nextUScalar1();
     311           0 :         shader = params.fUseColors4f
     312           0 :                          ? SkGradientShader::MakeRadial(center, radius, params.fColors4f,
     313           0 :                                                         params.fColorSpace, params.fStops,
     314             :                                                         params.fColorCount, params.fTileMode)
     315             :                          : SkGradientShader::MakeRadial(center, radius, params.fColors,
     316           0 :                                                         params.fStops, params.fColorCount,
     317           0 :                                                         params.fTileMode);
     318             :     } while (!shader);
     319           0 :     GrTest::TestAsFPArgs asFPArgs(d);
     320           0 :     sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(asFPArgs.args());
     321           0 :     GrAlwaysAssert(fp);
     322           0 :     return fp;
     323             : }
     324             : #endif
     325             : 
     326             : /////////////////////////////////////////////////////////////////////
     327             : 
     328           0 : void GrRadialGradient::GLSLRadialProcessor::emitCode(EmitArgs& args) {
     329           0 :     const GrRadialGradient& ge = args.fFp.cast<GrRadialGradient>();
     330           0 :     this->emitUniforms(args.fUniformHandler, ge);
     331           0 :     SkString t("length(");
     332           0 :     t.append(args.fFragBuilder->ensureCoords2D(args.fTransformedCoords[0]));
     333           0 :     t.append(")");
     334           0 :     this->emitColor(args.fFragBuilder,
     335             :                     args.fUniformHandler,
     336             :                     args.fShaderCaps,
     337             :                     ge, t.c_str(),
     338             :                     args.fOutputColor,
     339             :                     args.fInputColor,
     340           0 :                     args.fTexSamplers);
     341           0 : }
     342             : 
     343             : /////////////////////////////////////////////////////////////////////
     344             : 
     345           0 : sk_sp<GrFragmentProcessor> SkRadialGradient::asFragmentProcessor(const AsFPArgs& args) const {
     346           0 :     SkASSERT(args.fContext);
     347             : 
     348             :     SkMatrix matrix;
     349           0 :     if (!this->getLocalMatrix().invert(&matrix)) {
     350           0 :         return nullptr;
     351             :     }
     352           0 :     if (args.fLocalMatrix) {
     353             :         SkMatrix inv;
     354           0 :         if (!args.fLocalMatrix->invert(&inv)) {
     355           0 :             return nullptr;
     356             :         }
     357           0 :         matrix.postConcat(inv);
     358             :     }
     359           0 :     matrix.postConcat(fPtsToUnit);
     360           0 :     sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(fColorSpace.get(),
     361           0 :                                                                        args.fDstColorSpace);
     362             :     sk_sp<GrFragmentProcessor> inner(GrRadialGradient::Make(
     363           0 :         GrGradientEffect::CreateArgs(args.fContext, this, &matrix, fTileMode,
     364           0 :                                      std::move(colorSpaceXform), SkToBool(args.fDstColorSpace))));
     365           0 :     return GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner));
     366             : }
     367             : 
     368             : #endif
     369             : 
     370             : #ifndef SK_IGNORE_TO_STRING
     371           0 : void SkRadialGradient::toString(SkString* str) const {
     372           0 :     str->append("SkRadialGradient: (");
     373             : 
     374           0 :     str->append("center: (");
     375           0 :     str->appendScalar(fCenter.fX);
     376           0 :     str->append(", ");
     377           0 :     str->appendScalar(fCenter.fY);
     378           0 :     str->append(") radius: ");
     379           0 :     str->appendScalar(fRadius);
     380           0 :     str->append(" ");
     381             : 
     382           0 :     this->INHERITED::toString(str);
     383             : 
     384           0 :     str->append(")");
     385           0 : }
     386             : #endif

Generated by: LCOV version 1.13