LCOV - code coverage report
Current view: top level - gfx/2d - SVGTurbulenceRenderer-inl.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 142 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 77 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "2D.h"
       7             : #include "Filters.h"
       8             : #include "SIMD.h"
       9             : 
      10             : namespace mozilla {
      11             : namespace gfx {
      12             : 
      13             : template<TurbulenceType Type, bool Stitch, typename f32x4_t, typename i32x4_t, typename u8x16_t>
      14             : class SVGTurbulenceRenderer
      15             : {
      16             : public:
      17             :   SVGTurbulenceRenderer(const Size &aBaseFrequency, int32_t aSeed,
      18             :                         int aNumOctaves, const Rect &aTileRect);
      19             : 
      20             :   already_AddRefed<DataSourceSurface> Render(const IntSize &aSize, const Point &aOffset) const;
      21             : 
      22             : private:
      23             :   /* The turbulence calculation code is an adapted version of what
      24             :      appears in the SVG 1.1 specification:
      25             :          http://www.w3.org/TR/SVG11/filters.html#feTurbulence
      26             :   */
      27             : 
      28             :   struct StitchInfo {
      29             :     int32_t width;     // How much to subtract to wrap for stitching.
      30             :     int32_t height;
      31             :     int32_t wrapX;     // Minimum value to wrap.
      32             :     int32_t wrapY;
      33             :   };
      34             : 
      35             :   const static int sBSize = 0x100;
      36             :   const static int sBM = 0xff;
      37             :   void InitFromSeed(int32_t aSeed);
      38             :   void AdjustBaseFrequencyForStitch(const Rect &aTileRect);
      39             :   IntPoint AdjustForStitch(IntPoint aLatticePoint, const StitchInfo& aStitchInfo) const;
      40             :   StitchInfo CreateStitchInfo(const Rect &aTileRect) const;
      41             :   f32x4_t Noise2(Point aVec, const StitchInfo& aStitchInfo) const;
      42             :   i32x4_t Turbulence(const Point &aPoint) const;
      43             :   Point EquivalentNonNegativeOffset(const Point &aOffset) const;
      44             : 
      45             :   Size mBaseFrequency;
      46             :   int32_t mNumOctaves;
      47             :   StitchInfo mStitchInfo;
      48             :   bool mStitchable;
      49             :   TurbulenceType mType;
      50             :   uint8_t mLatticeSelector[sBSize];
      51             :   f32x4_t mGradient[sBSize][2];
      52             : };
      53             : 
      54             : namespace {
      55             : 
      56             : struct RandomNumberSource
      57             : {
      58           0 :   explicit RandomNumberSource(int32_t aSeed) : mLast(SetupSeed(aSeed)) {}
      59           0 :   int32_t Next() { mLast = Random(mLast); return mLast; }
      60             : 
      61             : private:
      62             :   static const int32_t RAND_M = 2147483647; /* 2**31 - 1 */
      63             :   static const int32_t RAND_A = 16807;      /* 7**5; primitive root of m */
      64             :   static const int32_t RAND_Q = 127773;     /* m / a */
      65             :   static const int32_t RAND_R = 2836;       /* m % a */
      66             : 
      67             :   /* Produces results in the range [1, 2**31 - 2].
      68             :      Algorithm is: r = (a * r) mod m
      69             :      where a = 16807 and m = 2**31 - 1 = 2147483647
      70             :      See [Park & Miller], CACM vol. 31 no. 10 p. 1195, Oct. 1988
      71             :      To test: the algorithm should produce the result 1043618065
      72             :      as the 10,000th generated number if the original seed is 1.
      73             :   */
      74             : 
      75             :   static int32_t
      76           0 :   SetupSeed(int32_t aSeed) {
      77           0 :     if (aSeed <= 0)
      78           0 :       aSeed = -(aSeed % (RAND_M - 1)) + 1;
      79           0 :     if (aSeed > RAND_M - 1)
      80           0 :       aSeed = RAND_M - 1;
      81           0 :     return aSeed;
      82             :   }
      83             : 
      84             :   static int32_t
      85           0 :   Random(int32_t aSeed)
      86             :   {
      87           0 :     int32_t result = RAND_A * (aSeed % RAND_Q) - RAND_R * (aSeed / RAND_Q);
      88           0 :     if (result <= 0)
      89           0 :       result += RAND_M;
      90           0 :     return result;
      91             :   }
      92             : 
      93             :   int32_t mLast;
      94             : };
      95             : 
      96             : } // unnamed namespace
      97             : 
      98             : template<TurbulenceType Type, bool Stitch, typename f32x4_t, typename i32x4_t, typename u8x16_t>
      99           0 : SVGTurbulenceRenderer<Type,Stitch,f32x4_t,i32x4_t,u8x16_t>::SVGTurbulenceRenderer(const Size &aBaseFrequency, int32_t aSeed,
     100             :                                                             int aNumOctaves, const Rect &aTileRect)
     101             :  : mBaseFrequency(aBaseFrequency)
     102           0 :  , mNumOctaves(aNumOctaves)
     103             : {
     104           0 :   InitFromSeed(aSeed);
     105             :   if (Stitch) {
     106           0 :     AdjustBaseFrequencyForStitch(aTileRect);
     107           0 :     mStitchInfo = CreateStitchInfo(aTileRect);
     108             :   }
     109           0 : }
     110             : 
     111             : template<typename T>
     112             : static void
     113           0 : Swap(T& a, T& b) {
     114           0 :   T c = a;
     115           0 :   a = b;
     116           0 :   b = c;
     117           0 : }
     118             : 
     119             : template<TurbulenceType Type, bool Stitch, typename f32x4_t, typename i32x4_t, typename u8x16_t>
     120             : void
     121           0 : SVGTurbulenceRenderer<Type,Stitch,f32x4_t,i32x4_t,u8x16_t>::InitFromSeed(int32_t aSeed)
     122             : {
     123           0 :   RandomNumberSource rand(aSeed);
     124             : 
     125             :   float gradient[4][sBSize][2];
     126           0 :   for (int32_t k = 0; k < 4; k++) {
     127           0 :     for (int32_t i = 0; i < sBSize; i++) {
     128             :       float a, b;
     129           0 :       do {
     130           0 :         a = float((rand.Next() % (sBSize + sBSize)) - sBSize) / sBSize;
     131           0 :         b = float((rand.Next() % (sBSize + sBSize)) - sBSize) / sBSize;
     132           0 :       } while (a == 0 && b == 0);
     133           0 :       float s = sqrt(a * a + b * b);
     134           0 :       gradient[k][i][0] = a / s;
     135           0 :       gradient[k][i][1] = b / s;
     136             :     }
     137             :   }
     138             : 
     139           0 :   for (int32_t i = 0; i < sBSize; i++) {
     140           0 :     mLatticeSelector[i] = i;
     141             :   }
     142           0 :   for (int32_t i1 = sBSize - 1; i1 > 0; i1--) {
     143           0 :     int32_t i2 = rand.Next() % sBSize;
     144           0 :     Swap(mLatticeSelector[i1], mLatticeSelector[i2]);
     145             :   }
     146             : 
     147           0 :   for (int32_t i = 0; i < sBSize; i++) {
     148             :     // Contrary to the code in the spec, we build the first lattice selector
     149             :     // lookup into mGradient so that we don't need to do it again for every
     150             :     // pixel.
     151             :     // We also change the order of the gradient indexing so that we can process
     152             :     // all four color channels at the same time.
     153           0 :     uint8_t j = mLatticeSelector[i];
     154           0 :     mGradient[i][0] = simd::FromF32<f32x4_t>(gradient[2][j][0], gradient[1][j][0],
     155             :                                              gradient[0][j][0], gradient[3][j][0]);
     156           0 :     mGradient[i][1] = simd::FromF32<f32x4_t>(gradient[2][j][1], gradient[1][j][1],
     157             :                                              gradient[0][j][1], gradient[3][j][1]);
     158             :   }
     159           0 : }
     160             : 
     161             : // Adjust aFreq such that aLength * AdjustForLength(aFreq, aLength) is integer
     162             : // and as close to aLength * aFreq as possible.
     163             : static inline float
     164           0 : AdjustForLength(float aFreq, float aLength)
     165             : {
     166           0 :   float lowFreq = floor(aLength * aFreq) / aLength;
     167           0 :   float hiFreq = ceil(aLength * aFreq) / aLength;
     168           0 :   if (aFreq / lowFreq < hiFreq / aFreq) {
     169           0 :     return lowFreq;
     170             :   }
     171           0 :   return hiFreq;
     172             : }
     173             : 
     174             : template<TurbulenceType Type, bool Stitch, typename f32x4_t, typename i32x4_t, typename u8x16_t>
     175             : void
     176           0 : SVGTurbulenceRenderer<Type,Stitch,f32x4_t,i32x4_t,u8x16_t>::AdjustBaseFrequencyForStitch(const Rect &aTileRect)
     177             : {
     178           0 :   mBaseFrequency = Size(AdjustForLength(mBaseFrequency.width, aTileRect.width),
     179           0 :                         AdjustForLength(mBaseFrequency.height, aTileRect.height));
     180           0 : }
     181             : 
     182             : template<TurbulenceType Type, bool Stitch, typename f32x4_t, typename i32x4_t, typename u8x16_t>
     183             : typename SVGTurbulenceRenderer<Type,Stitch,f32x4_t,i32x4_t,u8x16_t>::StitchInfo
     184           0 : SVGTurbulenceRenderer<Type,Stitch,f32x4_t,i32x4_t,u8x16_t>::CreateStitchInfo(const Rect &aTileRect) const
     185             : {
     186             :   StitchInfo stitch;
     187           0 :   stitch.width = int32_t(floorf(aTileRect.width * mBaseFrequency.width + 0.5f));
     188           0 :   stitch.height = int32_t(floorf(aTileRect.height * mBaseFrequency.height + 0.5f));
     189           0 :   stitch.wrapX = int32_t(aTileRect.x * mBaseFrequency.width) + stitch.width;
     190           0 :   stitch.wrapY = int32_t(aTileRect.y * mBaseFrequency.height) + stitch.height;
     191           0 :   return stitch;
     192             : }
     193             : 
     194             : static MOZ_ALWAYS_INLINE Float
     195           0 : SCurve(Float t)
     196             : {
     197           0 :   return t * t * (3 - 2 * t);
     198             : }
     199             : 
     200             : static MOZ_ALWAYS_INLINE Point
     201           0 : SCurve(Point t)
     202             : {
     203           0 :   return Point(SCurve(t.x), SCurve(t.y));
     204             : }
     205             : 
     206             : template<typename f32x4_t>
     207             : static MOZ_ALWAYS_INLINE f32x4_t
     208           0 : BiMix(const f32x4_t& aa, const f32x4_t& ab,
     209             :       const f32x4_t& ba, const f32x4_t& bb, Point s)
     210             : {
     211           0 :   return simd::MixF32(simd::MixF32(aa, ab, s.x),
     212           0 :                       simd::MixF32(ba, bb, s.x), s.y);
     213             : }
     214             : 
     215             : template<TurbulenceType Type, bool Stitch, typename f32x4_t, typename i32x4_t, typename u8x16_t>
     216             : IntPoint
     217           0 : SVGTurbulenceRenderer<Type,Stitch,f32x4_t,i32x4_t,u8x16_t>::AdjustForStitch(IntPoint aLatticePoint,
     218             :                                                       const StitchInfo& aStitchInfo) const
     219             : {
     220             :   if (Stitch) {
     221           0 :     if (aLatticePoint.x >= aStitchInfo.wrapX) {
     222           0 :       aLatticePoint.x -= aStitchInfo.width;
     223             :     }
     224           0 :     if (aLatticePoint.y >= aStitchInfo.wrapY) {
     225           0 :       aLatticePoint.y -= aStitchInfo.height;
     226             :     }
     227             :   }
     228           0 :   return aLatticePoint;
     229             : }
     230             : 
     231             : template<TurbulenceType Type, bool Stitch, typename f32x4_t, typename i32x4_t, typename u8x16_t>
     232             : f32x4_t
     233           0 : SVGTurbulenceRenderer<Type,Stitch,f32x4_t,i32x4_t,u8x16_t>::Noise2(Point aVec, const StitchInfo& aStitchInfo) const
     234             : {
     235             :   // aVec is guaranteed to be non-negative, so casting to int32_t always
     236             :   // rounds towards negative infinity.
     237           0 :   IntPoint topLeftLatticePoint(int32_t(aVec.x), int32_t(aVec.y));
     238           0 :   Point r = aVec - topLeftLatticePoint; // fractional offset
     239             : 
     240           0 :   IntPoint b0 = AdjustForStitch(topLeftLatticePoint, aStitchInfo);
     241           0 :   IntPoint b1 = AdjustForStitch(b0 + IntPoint(1, 1), aStitchInfo);
     242             : 
     243           0 :   uint8_t i = mLatticeSelector[b0.x & sBM];
     244           0 :   uint8_t j = mLatticeSelector[b1.x & sBM];
     245             : 
     246           0 :   const f32x4_t* qua = mGradient[(i + b0.y) & sBM];
     247           0 :   const f32x4_t* qub = mGradient[(i + b1.y) & sBM];
     248           0 :   const f32x4_t* qva = mGradient[(j + b0.y) & sBM];
     249           0 :   const f32x4_t* qvb = mGradient[(j + b1.y) & sBM];
     250             : 
     251           0 :   return BiMix(simd::WSumF32(qua[0], qua[1], r.x, r.y),
     252           0 :                simd::WSumF32(qva[0], qva[1], r.x - 1.f, r.y),
     253           0 :                simd::WSumF32(qub[0], qub[1], r.x, r.y - 1.f),
     254           0 :                simd::WSumF32(qvb[0], qvb[1], r.x - 1.f, r.y - 1.f),
     255           0 :                SCurve(r));
     256             : }
     257             : 
     258             : template<typename f32x4_t, typename i32x4_t, typename u8x16_t>
     259             : static inline i32x4_t
     260           0 : ColorToBGRA(f32x4_t aUnscaledUnpreFloat)
     261             : {
     262             :   // Color is an unpremultiplied float vector where 1.0f means white. We will
     263             :   // convert it into an integer vector where 255 means white.
     264           0 :   f32x4_t alpha = simd::SplatF32<3>(aUnscaledUnpreFloat);
     265           0 :   f32x4_t scaledUnpreFloat = simd::MulF32(aUnscaledUnpreFloat, simd::FromF32<f32x4_t>(255));
     266           0 :   i32x4_t scaledUnpreInt = simd::F32ToI32(scaledUnpreFloat);
     267             : 
     268             :   // Multiply all channels with alpha.
     269           0 :   i32x4_t scaledPreInt = simd::F32ToI32(simd::MulF32(scaledUnpreFloat, alpha));
     270             : 
     271             :   // Use the premultiplied color channels and the unpremultiplied alpha channel.
     272           0 :   i32x4_t alphaMask = simd::From32<i32x4_t>(0, 0, 0, -1);
     273           0 :   return simd::Pick(alphaMask, scaledPreInt, scaledUnpreInt);
     274             : }
     275             : 
     276             : template<TurbulenceType Type, bool Stitch, typename f32x4_t, typename i32x4_t, typename u8x16_t>
     277             : i32x4_t
     278           0 : SVGTurbulenceRenderer<Type,Stitch,f32x4_t,i32x4_t,u8x16_t>::Turbulence(const Point &aPoint) const
     279             : {
     280           0 :   StitchInfo stitchInfo = mStitchInfo;
     281           0 :   f32x4_t sum = simd::FromF32<f32x4_t>(0);
     282           0 :   Point vec(aPoint.x * mBaseFrequency.width, aPoint.y * mBaseFrequency.height);
     283           0 :   f32x4_t ratio = simd::FromF32<f32x4_t>(1);
     284             : 
     285           0 :   for (int octave = 0; octave < mNumOctaves; octave++) {
     286           0 :     f32x4_t thisOctave = Noise2(vec, stitchInfo);
     287             :     if (Type == TURBULENCE_TYPE_TURBULENCE) {
     288           0 :       thisOctave = simd::AbsF32(thisOctave);
     289             :     }
     290           0 :     sum = simd::AddF32(sum, simd::DivF32(thisOctave, ratio));
     291           0 :     vec = vec * 2;
     292           0 :     ratio = simd::MulF32(ratio, simd::FromF32<f32x4_t>(2));
     293             : 
     294             :     if (Stitch) {
     295           0 :       stitchInfo.width *= 2;
     296           0 :       stitchInfo.wrapX *= 2;
     297           0 :       stitchInfo.height *= 2;
     298           0 :       stitchInfo.wrapY *= 2;
     299             :     }
     300             :   }
     301             : 
     302             :   if (Type == TURBULENCE_TYPE_FRACTAL_NOISE) {
     303           0 :     sum = simd::DivF32(simd::AddF32(sum, simd::FromF32<f32x4_t>(1)), simd::FromF32<f32x4_t>(2));
     304             :   }
     305           0 :   return ColorToBGRA<f32x4_t,i32x4_t,u8x16_t>(sum);
     306             : }
     307             : 
     308             : static inline Float
     309           0 : MakeNonNegative(Float aValue, Float aIncrementSize)
     310             : {
     311           0 :   if (aValue >= 0) {
     312           0 :     return aValue;
     313             :   }
     314           0 :   return aValue + ceilf(-aValue / aIncrementSize) * aIncrementSize;
     315             : }
     316             : 
     317             : template<TurbulenceType Type, bool Stitch, typename f32x4_t, typename i32x4_t, typename u8x16_t>
     318             : Point
     319           0 : SVGTurbulenceRenderer<Type,Stitch,f32x4_t,i32x4_t,u8x16_t>::EquivalentNonNegativeOffset(const Point &aOffset) const
     320             : {
     321           0 :   Size basePeriod = Stitch ? Size(mStitchInfo.width, mStitchInfo.height) :
     322           0 :                              Size(sBSize, sBSize);
     323           0 :   Size repeatingSize(basePeriod.width / mBaseFrequency.width,
     324           0 :                      basePeriod.height / mBaseFrequency.height);
     325           0 :   return Point(MakeNonNegative(aOffset.x, repeatingSize.width),
     326           0 :                MakeNonNegative(aOffset.y, repeatingSize.height));
     327             : }
     328             : 
     329             : template<TurbulenceType Type, bool Stitch, typename f32x4_t, typename i32x4_t, typename u8x16_t>
     330             : already_AddRefed<DataSourceSurface>
     331           0 : SVGTurbulenceRenderer<Type,Stitch,f32x4_t,i32x4_t,u8x16_t>::Render(const IntSize &aSize, const Point &aOffset) const
     332             : {
     333             :   RefPtr<DataSourceSurface> target =
     334           0 :     Factory::CreateDataSourceSurface(aSize, SurfaceFormat::B8G8R8A8);
     335           0 :   if (!target) {
     336           0 :     return nullptr;
     337             :   }
     338             : 
     339           0 :   uint8_t* targetData = target->GetData();
     340           0 :   uint32_t stride = target->Stride();
     341             : 
     342           0 :   Point startOffset = EquivalentNonNegativeOffset(aOffset);
     343             : 
     344           0 :   for (int32_t y = 0; y < aSize.height; y++) {
     345           0 :     for (int32_t x = 0; x < aSize.width; x += 4) {
     346           0 :       int32_t targIndex = y * stride + x * 4;
     347           0 :       i32x4_t a = Turbulence(startOffset + Point(x, y));
     348           0 :       i32x4_t b = Turbulence(startOffset + Point(x + 1, y));
     349           0 :       i32x4_t c = Turbulence(startOffset + Point(x + 2, y));
     350           0 :       i32x4_t d = Turbulence(startOffset + Point(x + 3, y));
     351           0 :       u8x16_t result1234 = simd::PackAndSaturate32To8(a, b, c, d);
     352           0 :       simd::Store8(&targetData[targIndex], result1234);
     353             :     }
     354             :   }
     355             : 
     356           0 :   return target.forget();
     357             : }
     358             : 
     359             : } // namespace gfx
     360             : } // namespace mozilla

Generated by: LCOV version 1.13