gfx/skia/trunk/src/opts/SkBitmapProcState_opts_SSSE3.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /*
     2  * Copyright 2012 The Android Open Source Project
     3  *
     4  * Use of this source code is governed by a BSD-style license that can be
     5  * found in the LICENSE file.
     6  */
     8 #include "SkBitmapProcState_opts_SSSE3.h"
     9 #include "SkPaint.h"
    10 #include "SkUtils.h"
    12 /* With the exception of the Android framework we always build the SSSE3 functions
    13  * and enable the caller to determine SSSE3 support.  However for the Android framework
    14  * if the device does not support SSSE3 then the compiler will not supply the required
    15  * -mssse3 option needed to build this file, so instead we provide a stub implementation.
    16  */
    17 #if !defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) || SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSSE3
    19 #include <tmmintrin.h>  // SSSE3
    21 // adding anonymous namespace seemed to force gcc to inline directly the
    22 // instantiation, instead of creating the functions
    23 // S32_generic_D32_filter_DX_SSSE3<true> and
    24 // S32_generic_D32_filter_DX_SSSE3<false> which were then called by the
    25 // external functions.
    26 namespace {
    27 // In this file, variations for alpha and non alpha versions are implemented
    28 // with a template, as it makes the code more compact and a bit easier to
    29 // maintain, while making the compiler generate the same exact code as with
    30 // two functions that only differ by a few lines.
    33 // Prepare all necessary constants for a round of processing for two pixel
    34 // pairs.
    35 // @param xy is the location where the xy parameters for four pixels should be
    36 //           read from. It is identical in concept with argument two of
    37 //           S32_{opaque}_D32_filter_DX methods.
    38 // @param mask_3FFF vector of 32 bit constants containing 3FFF,
    39 //                  suitable to mask the bottom 14 bits of a XY value.
    40 // @param mask_000F vector of 32 bit constants containing 000F,
    41 //                  suitable to mask the bottom 4 bits of a XY value.
    42 // @param sixteen_8bit vector of 8 bit components containing the value 16.
    43 // @param mask_dist_select vector of 8 bit components containing the shuffling
    44 //                         parameters to reorder x[0-3] parameters.
    45 // @param all_x_result vector of 8 bit components that will contain the
    46 //              (4x(x3), 4x(x2), 4x(x1), 4x(x0)) upon return.
    47 // @param sixteen_minus_x vector of 8 bit components, containing
    48 //              (4x(16 - x3), 4x(16 - x2), 4x(16 - x1), 4x(16 - x0))
    49 inline void PrepareConstantsTwoPixelPairs(const uint32_t* xy,
    50                                           const __m128i& mask_3FFF,
    51                                           const __m128i& mask_000F,
    52                                           const __m128i& sixteen_8bit,
    53                                           const __m128i& mask_dist_select,
    54                                           __m128i* all_x_result,
    55                                           __m128i* sixteen_minus_x,
    56                                           int* x0,
    57                                           int* x1) {
    58     const __m128i xx = _mm_loadu_si128(reinterpret_cast<const __m128i *>(xy));
    60     // 4 delta X
    61     // (x03, x02, x01, x00)
    62     const __m128i x0_wide = _mm_srli_epi32(xx, 18);
    63     // (x13, x12, x11, x10)
    64     const __m128i x1_wide = _mm_and_si128(xx, mask_3FFF);
    66     _mm_storeu_si128(reinterpret_cast<__m128i *>(x0), x0_wide);
    67     _mm_storeu_si128(reinterpret_cast<__m128i *>(x1), x1_wide);
    69     __m128i all_x = _mm_and_si128(_mm_srli_epi32(xx, 14), mask_000F);
    71     // (4x(x3), 4x(x2), 4x(x1), 4x(x0))
    72     all_x = _mm_shuffle_epi8(all_x, mask_dist_select);
    74     *all_x_result = all_x;
    75     // (4x(16-x3), 4x(16-x2), 4x(16-x1), 4x(16-x0))
    76     *sixteen_minus_x = _mm_sub_epi8(sixteen_8bit, all_x);
    77 }
    79 // Prepare all necessary constants for a round of processing for two pixel
    80 // pairs.
    81 // @param xy is the location where the xy parameters for four pixels should be
    82 //           read from. It is identical in concept with argument two of
    83 //           S32_{opaque}_D32_filter_DXDY methods.
    84 // @param mask_3FFF vector of 32 bit constants containing 3FFF,
    85 //                  suitable to mask the bottom 14 bits of a XY value.
    86 // @param mask_000F vector of 32 bit constants containing 000F,
    87 //                  suitable to mask the bottom 4 bits of a XY value.
    88 // @param sixteen_8bit vector of 8 bit components containing the value 16.
    89 // @param mask_dist_select vector of 8 bit components containing the shuffling
    90 //                         parameters to reorder x[0-3] parameters.
    91 // @param all_xy_result vector of 8 bit components that will contain the
    92 //              (4x(y1), 4x(y0), 4x(x1), 4x(x0)) upon return.
    93 // @param sixteen_minus_x vector of 8 bit components, containing
    94 //              (4x(16-y1), 4x(16-y0), 4x(16-x1), 4x(16-x0)).
    95 inline void PrepareConstantsTwoPixelPairsDXDY(const uint32_t* xy,
    96                                               const __m128i& mask_3FFF,
    97                                               const __m128i& mask_000F,
    98                                               const __m128i& sixteen_8bit,
    99                                               const __m128i& mask_dist_select,
   100                                               __m128i* all_xy_result,
   101                                               __m128i* sixteen_minus_xy,
   102                                               int* xy0, int* xy1) {
   103     const __m128i xy_wide =
   104                         _mm_loadu_si128(reinterpret_cast<const __m128i *>(xy));
   106     // (x10, y10, x00, y00)
   107     __m128i xy0_wide = _mm_srli_epi32(xy_wide, 18);
   108     // (y10, y00, x10, x00)
   109     xy0_wide =  _mm_shuffle_epi32(xy0_wide, _MM_SHUFFLE(2, 0, 3, 1));
   110     // (x11, y11, x01, y01)
   111     __m128i xy1_wide = _mm_and_si128(xy_wide, mask_3FFF);
   112     // (y11, y01, x11, x01)
   113     xy1_wide = _mm_shuffle_epi32(xy1_wide, _MM_SHUFFLE(2, 0, 3, 1));
   115     _mm_storeu_si128(reinterpret_cast<__m128i *>(xy0), xy0_wide);
   116     _mm_storeu_si128(reinterpret_cast<__m128i *>(xy1), xy1_wide);
   118     // (x1, y1, x0, y0)
   119     __m128i all_xy = _mm_and_si128(_mm_srli_epi32(xy_wide, 14), mask_000F);
   120     // (y1, y0, x1, x0)
   121     all_xy = _mm_shuffle_epi32(all_xy, _MM_SHUFFLE(2, 0, 3, 1));
   122     // (4x(y1), 4x(y0), 4x(x1), 4x(x0))
   123     all_xy = _mm_shuffle_epi8(all_xy, mask_dist_select);
   125     *all_xy_result = all_xy;
   126     // (4x(16-y1), 4x(16-y0), 4x(16-x1), 4x(16-x0))
   127     *sixteen_minus_xy = _mm_sub_epi8(sixteen_8bit, all_xy);
   128 }
   130 // Helper function used when processing one pixel pair.
   131 // @param pixel0..3 are the four input pixels
   132 // @param scale_x vector of 8 bit components to multiply the pixel[0:3]. This
   133 //                will contain (4x(x1, 16-x1), 4x(x0, 16-x0))
   134 //                or (4x(x3, 16-x3), 4x(x2, 16-x2))
   135 // @return a vector of 16 bit components containing:
   136 // (Aa2 * (16 - x1) + Aa3 * x1, ... , Ra0 * (16 - x0) + Ra1 * x0)
   137 inline __m128i ProcessPixelPairHelper(uint32_t pixel0,
   138                                       uint32_t pixel1,
   139                                       uint32_t pixel2,
   140                                       uint32_t pixel3,
   141                                       const __m128i& scale_x) {
   142     __m128i a0, a1, a2, a3;
   143     // Load 2 pairs of pixels
   144     a0 = _mm_cvtsi32_si128(pixel0);
   145     a1 = _mm_cvtsi32_si128(pixel1);
   147     // Interleave pixels.
   148     // (0, 0, 0, 0, 0, 0, 0, 0, Aa1, Aa0, Ba1, Ba0, Ga1, Ga0, Ra1, Ra0)
   149     a0 = _mm_unpacklo_epi8(a0, a1);
   151     a2 = _mm_cvtsi32_si128(pixel2);
   152     a3 = _mm_cvtsi32_si128(pixel3);
   153     // (0, 0, 0, 0, 0, 0, 0, 0, Aa3, Aa2, Ba3, Ba2, Ga3, Ga2, Ra3, Ra2)
   154     a2 = _mm_unpacklo_epi8(a2, a3);
   156     // two pairs of pixel pairs, interleaved.
   157     // (Aa3, Aa2, Ba3, Ba2, Ga3, Ga2, Ra3, Ra2,
   158     //  Aa1, Aa0, Ba1, Ba0, Ga1, Ga0, Ra1, Ra0)
   159     a0 = _mm_unpacklo_epi64(a0, a2);
   161     // multiply and sum to 16 bit components.
   162     // (Aa2 * (16 - x1) + Aa3 * x1, ... , Ra0 * (16 - x0) + Ra1 * x0)
   163     // At that point, we use up a bit less than 12 bits for each 16 bit
   164     // component:
   165     // All components are less than 255. So,
   166     // C0 * (16 - x) + C1 * x <= 255 * (16 - x) + 255 * x = 255 * 16.
   167     return _mm_maddubs_epi16(a0, scale_x);
   168 }
   170 // Scale back the results after multiplications to the [0:255] range, and scale
   171 // by alpha when has_alpha is true.
   172 // Depending on whether one set or two sets of multiplications had been applied,
   173 // the results have to be shifted by four places (dividing by 16), or shifted
   174 // by eight places (dividing by 256), since each multiplication is by a quantity
   175 // in the range [0:16].
   176 template<bool has_alpha, int scale>
   177 inline __m128i ScaleFourPixels(__m128i* pixels,
   178                                const __m128i& alpha) {
   179     // Divide each 16 bit component by 16 (or 256 depending on scale).
   180     *pixels = _mm_srli_epi16(*pixels, scale);
   182     if (has_alpha) {
   183         // Multiply by alpha.
   184         *pixels = _mm_mullo_epi16(*pixels, alpha);
   186         // Divide each 16 bit component by 256.
   187         *pixels = _mm_srli_epi16(*pixels, 8);
   188     }
   189     return *pixels;
   190 }
   192 // Wrapper to calculate two output pixels from four input pixels. The
   193 // arguments are the same as ProcessPixelPairHelper. Technically, there are
   194 // eight input pixels, but since sub_y == 0, the factors applied to half of the
   195 // pixels is zero (sub_y), and are therefore omitted here to save on some
   196 // processing.
   197 // @param alpha when has_alpha is true, scale all resulting components by this
   198 //              value.
   199 // @return a vector of 16 bit components containing:
   200 // ((Aa2 * (16 - x1) + Aa3 * x1) * alpha, ...,
   201 // (Ra0 * (16 - x0) + Ra1 * x0) * alpha) (when has_alpha is true)
   202 // otherwise
   203 // (Aa2 * (16 - x1) + Aa3 * x1, ... , Ra0 * (16 - x0) + Ra1 * x0)
   204 // In both cases, the results are renormalized (divided by 16) to match the
   205 // expected formats when storing back the results into memory.
   206 template<bool has_alpha>
   207 inline __m128i ProcessPixelPairZeroSubY(uint32_t pixel0,
   208                                         uint32_t pixel1,
   209                                         uint32_t pixel2,
   210                                         uint32_t pixel3,
   211                                         const __m128i& scale_x,
   212                                         const __m128i& alpha) {
   213     __m128i sum = ProcessPixelPairHelper(pixel0, pixel1, pixel2, pixel3,
   214                                          scale_x);
   215     return ScaleFourPixels<has_alpha, 4>(&sum, alpha);
   216 }
   218 // Same as ProcessPixelPairZeroSubY, expect processing one output pixel at a
   219 // time instead of two. As in the above function, only two pixels are needed
   220 // to generate a single pixel since sub_y == 0.
   221 // @return same as ProcessPixelPairZeroSubY, except that only the bottom 4
   222 // 16 bit components are set.
   223 template<bool has_alpha>
   224 inline __m128i ProcessOnePixelZeroSubY(uint32_t pixel0,
   225                                        uint32_t pixel1,
   226                                        __m128i scale_x,
   227                                        __m128i alpha) {
   228     __m128i a0 = _mm_cvtsi32_si128(pixel0);
   229     __m128i a1 = _mm_cvtsi32_si128(pixel1);
   231     // Interleave
   232     a0 = _mm_unpacklo_epi8(a0, a1);
   234     // (a0 * (16-x) + a1 * x)
   235     __m128i sum = _mm_maddubs_epi16(a0, scale_x);
   237     return ScaleFourPixels<has_alpha, 4>(&sum, alpha);
   238 }
   240 // Methods when sub_y != 0
   243 // Same as ProcessPixelPairHelper, except that the values are scaled by y.
   244 // @param y vector of 16 bit components containing 'y' values. There are two
   245 //        cases in practice, where y will contain the sub_y constant, or will
   246 //        contain the 16 - sub_y constant.
   247 // @return vector of 16 bit components containing:
   248 // (y * (Aa2 * (16 - x1) + Aa3 * x1), ... , y * (Ra0 * (16 - x0) + Ra1 * x0))
   249 inline __m128i ProcessPixelPair(uint32_t pixel0,
   250                                 uint32_t pixel1,
   251                                 uint32_t pixel2,
   252                                 uint32_t pixel3,
   253                                 const __m128i& scale_x,
   254                                 const __m128i& y) {
   255     __m128i sum = ProcessPixelPairHelper(pixel0, pixel1, pixel2, pixel3,
   256                                          scale_x);
   258     // first row times 16-y or y depending on whether 'y' represents one or
   259     // the other.
   260     // Values will be up to 255 * 16 * 16 = 65280.
   261     // (y * (Aa2 * (16 - x1) + Aa3 * x1), ... ,
   262     //  y * (Ra0 * (16 - x0) + Ra1 * x0))
   263     sum = _mm_mullo_epi16(sum, y);
   265     return sum;
   266 }
   268 // Process two pixel pairs out of eight input pixels.
   269 // In other methods, the distinct pixels are passed one by one, but in this
   270 // case, the rows, and index offsets to the pixels into the row are passed
   271 // to generate the 8 pixels.
   272 // @param row0..1 top and bottom row where to find input pixels.
   273 // @param x0..1 offsets into the row for all eight input pixels.
   274 // @param all_y vector of 16 bit components containing the constant sub_y
   275 // @param neg_y vector of 16 bit components containing the constant 16 - sub_y
   276 // @param alpha vector of 16 bit components containing the alpha value to scale
   277 //        the results by, when has_alpha is true.
   278 // @return
   279 // (alpha * ((16-y) * (Aa2  * (16-x1) + Aa3  * x1) +
   280 //             y    * (Aa2' * (16-x1) + Aa3' * x1)),
   281 // ...
   282 //  alpha * ((16-y) * (Ra0  * (16-x0) + Ra1 * x0) +
   283 //             y    * (Ra0' * (16-x0) + Ra1' * x0))
   284 // With the factor alpha removed when has_alpha is false.
   285 // The values are scaled back to 16 bit components, but with only the bottom
   286 // 8 bits being set.
   287 template<bool has_alpha>
   288 inline __m128i ProcessTwoPixelPairs(const uint32_t* row0,
   289                                     const uint32_t* row1,
   290                                     const int* x0,
   291                                     const int* x1,
   292                                     const __m128i& scale_x,
   293                                     const __m128i& all_y,
   294                                     const __m128i& neg_y,
   295                                     const __m128i& alpha) {
   296     __m128i sum0 = ProcessPixelPair(
   297         row0[x0[0]], row0[x1[0]], row0[x0[1]], row0[x1[1]],
   298         scale_x, neg_y);
   299     __m128i sum1 = ProcessPixelPair(
   300         row1[x0[0]], row1[x1[0]], row1[x0[1]], row1[x1[1]],
   301         scale_x, all_y);
   303     // 2 samples fully summed.
   304     // ((16-y) * (Aa2 * (16-x1) + Aa3 * x1) +
   305     //  y * (Aa2' * (16-x1) + Aa3' * x1),
   306     // ...
   307     //  (16-y) * (Ra0 * (16 - x0) + Ra1 * x0)) +
   308     //  y * (Ra0' * (16-x0) + Ra1' * x0))
   309     // Each component, again can be at most 256 * 255 = 65280, so no overflow.
   310     sum0 = _mm_add_epi16(sum0, sum1);
   312     return ScaleFourPixels<has_alpha, 8>(&sum0, alpha);
   313 }
   315 // Similar to ProcessTwoPixelPairs except the pixel indexes.
   316 template<bool has_alpha>
   317 inline __m128i ProcessTwoPixelPairsDXDY(const uint32_t* row00,
   318                                         const uint32_t* row01,
   319                                         const uint32_t* row10,
   320                                         const uint32_t* row11,
   321                                         const int* xy0,
   322                                         const int* xy1,
   323                                         const __m128i& scale_x,
   324                                         const __m128i& all_y,
   325                                         const __m128i& neg_y,
   326                                         const __m128i& alpha) {
   327     // first row
   328     __m128i sum0 = ProcessPixelPair(
   329         row00[xy0[0]], row00[xy1[0]], row10[xy0[1]], row10[xy1[1]],
   330         scale_x, neg_y);
   331     // second row
   332     __m128i sum1 = ProcessPixelPair(
   333         row01[xy0[0]], row01[xy1[0]], row11[xy0[1]], row11[xy1[1]],
   334         scale_x, all_y);
   336     // 2 samples fully summed.
   337     // ((16-y1) * (Aa2 * (16-x1) + Aa3 * x1) +
   338     //  y0 * (Aa2' * (16-x1) + Aa3' * x1),
   339     // ...
   340     //  (16-y0) * (Ra0 * (16 - x0) + Ra1 * x0)) +
   341     //  y0 * (Ra0' * (16-x0) + Ra1' * x0))
   342     // Each component, again can be at most 256 * 255 = 65280, so no overflow.
   343     sum0 = _mm_add_epi16(sum0, sum1);
   345     return ScaleFourPixels<has_alpha, 8>(&sum0, alpha);
   346 }
   349 // Same as ProcessPixelPair, except that performing the math one output pixel
   350 // at a time. This means that only the bottom four 16 bit components are set.
   351 inline __m128i ProcessOnePixel(uint32_t pixel0, uint32_t pixel1,
   352                                const __m128i& scale_x, const __m128i& y) {
   353     __m128i a0 = _mm_cvtsi32_si128(pixel0);
   354     __m128i a1 = _mm_cvtsi32_si128(pixel1);
   356     // Interleave
   357     // (0, 0, 0, 0, 0, 0, 0, 0, Aa1, Aa0, Ba1, Ba0, Ga1, Ga0, Ra1, Ra0)
   358     a0 = _mm_unpacklo_epi8(a0, a1);
   360     // (a0 * (16-x) + a1 * x)
   361     a0 = _mm_maddubs_epi16(a0, scale_x);
   363     // scale row by y
   364     return _mm_mullo_epi16(a0, y);
   365 }
   367 // Notes about the various tricks that are used in this implementation:
   368 // - specialization for sub_y == 0.
   369 // Statistically, 1/16th of the samples will have sub_y == 0. When this
   370 // happens, the math goes from:
   371 // (16 - x)*(16 - y)*a00 + x*(16 - y)*a01 + (16 - x)*y*a10 + x*y*a11
   372 // to:
   373 // (16 - x)*a00 + 16*x*a01
   374 // much simpler. The simplification makes for an easy boost in performance.
   375 // - calculating 4 output pixels at a time.
   376 //  This allows loading the coefficients x0 and x1 and shuffling them to the
   377 // optimum location only once per loop, instead of twice per loop.
   378 // This also allows us to store the four pixels with a single store.
   379 // - Use of 2 special SSSE3 instructions (comparatively to the SSE2 instruction
   380 // version):
   381 // _mm_shuffle_epi8 : this allows us to spread the coefficients x[0-3] loaded
   382 // in 32 bit values to 8 bit values repeated four times.
   383 // _mm_maddubs_epi16 : this allows us to perform multiplications and additions
   384 // in one swoop of 8bit values storing the results in 16 bit values. This
   385 // instruction is actually crucial for the speed of the implementation since
   386 // as one can see in the SSE2 implementation, all inputs have to be used as
   387 // 16 bits because the results are 16 bits. This basically allows us to process
   388 // twice as many pixel components per iteration.
   389 //
   390 // As a result, this method behaves faster than the traditional SSE2. The actual
   391 // boost varies greatly on the underlying architecture.
   392 template<bool has_alpha>
   393 void S32_generic_D32_filter_DX_SSSE3(const SkBitmapProcState& s,
   394                                      const uint32_t* xy,
   395                                      int count, uint32_t* colors) {
   396     SkASSERT(count > 0 && colors != NULL);
   397     SkASSERT(s.fFilterLevel != SkPaint::kNone_FilterLevel);
   398     SkASSERT(s.fBitmap->config() == SkBitmap::kARGB_8888_Config);
   399     if (has_alpha) {
   400         SkASSERT(s.fAlphaScale < 256);
   401     } else {
   402         SkASSERT(s.fAlphaScale == 256);
   403     }
   405     const uint8_t* src_addr =
   406             static_cast<const uint8_t*>(s.fBitmap->getPixels());
   407     const size_t rb = s.fBitmap->rowBytes();
   408     const uint32_t XY = *xy++;
   409     const unsigned y0 = XY >> 14;
   410     const uint32_t* row0 =
   411             reinterpret_cast<const uint32_t*>(src_addr + (y0 >> 4) * rb);
   412     const uint32_t* row1 =
   413             reinterpret_cast<const uint32_t*>(src_addr + (XY & 0x3FFF) * rb);
   414     const unsigned sub_y = y0 & 0xF;
   416     // vector constants
   417     const __m128i mask_dist_select = _mm_set_epi8(12, 12, 12, 12,
   418                                                   8,  8,  8,  8,
   419                                                   4,  4,  4,  4,
   420                                                   0,  0,  0,  0);
   421     const __m128i mask_3FFF = _mm_set1_epi32(0x3FFF);
   422     const __m128i mask_000F = _mm_set1_epi32(0x000F);
   423     const __m128i sixteen_8bit = _mm_set1_epi8(16);
   424     // (0, 0, 0, 0, 0, 0, 0, 0)
   425     const __m128i zero = _mm_setzero_si128();
   427     __m128i alpha = _mm_setzero_si128();
   428     if (has_alpha)
   429         // 8x(alpha)
   430         alpha = _mm_set1_epi16(s.fAlphaScale);
   432     if (sub_y == 0) {
   433         // Unroll 4x, interleave bytes, use pmaddubsw (all_x is small)
   434         while (count > 3) {
   435             count -= 4;
   437             int x0[4];
   438             int x1[4];
   439             __m128i all_x, sixteen_minus_x;
   440             PrepareConstantsTwoPixelPairs(xy, mask_3FFF, mask_000F,
   441                                           sixteen_8bit, mask_dist_select,
   442                                           &all_x, &sixteen_minus_x, x0, x1);
   443             xy += 4;
   445             // First pair of pixel pairs.
   446             // (4x(x1, 16-x1), 4x(x0, 16-x0))
   447             __m128i scale_x;
   448             scale_x = _mm_unpacklo_epi8(sixteen_minus_x, all_x);
   450             __m128i sum0 = ProcessPixelPairZeroSubY<has_alpha>(
   451                 row0[x0[0]], row0[x1[0]], row0[x0[1]], row0[x1[1]],
   452                 scale_x, alpha);
   454             // second pair of pixel pairs
   455             // (4x (x3, 16-x3), 4x (16-x2, x2))
   456             scale_x = _mm_unpackhi_epi8(sixteen_minus_x, all_x);
   458             __m128i sum1 = ProcessPixelPairZeroSubY<has_alpha>(
   459                 row0[x0[2]], row0[x1[2]], row0[x0[3]], row0[x1[3]],
   460                 scale_x, alpha);
   462             // Pack lower 4 16 bit values of sum into lower 4 bytes.
   463             sum0 = _mm_packus_epi16(sum0, sum1);
   465             // Extract low int and store.
   466             _mm_storeu_si128(reinterpret_cast<__m128i *>(colors), sum0);
   468             colors += 4;
   469         }
   471         // handle remainder
   472         while (count-- > 0) {
   473             uint32_t xx = *xy++;  // x0:14 | 4 | x1:14
   474             unsigned x0 = xx >> 18;
   475             unsigned x1 = xx & 0x3FFF;
   477             // 16x(x)
   478             const __m128i all_x = _mm_set1_epi8((xx >> 14) & 0x0F);
   480             // (16x(16-x))
   481             __m128i scale_x = _mm_sub_epi8(sixteen_8bit, all_x);
   483             scale_x = _mm_unpacklo_epi8(scale_x, all_x);
   485             __m128i sum = ProcessOnePixelZeroSubY<has_alpha>(
   486                 row0[x0], row0[x1],
   487                 scale_x, alpha);
   489             // Pack lower 4 16 bit values of sum into lower 4 bytes.
   490             sum = _mm_packus_epi16(sum, zero);
   492             // Extract low int and store.
   493             *colors++ = _mm_cvtsi128_si32(sum);
   494         }
   495     } else {  // more general case, y != 0
   496         // 8x(16)
   497         const __m128i sixteen_16bit = _mm_set1_epi16(16);
   499         // 8x (y)
   500         const __m128i all_y = _mm_set1_epi16(sub_y);
   502         // 8x (16-y)
   503         const __m128i neg_y = _mm_sub_epi16(sixteen_16bit, all_y);
   505         // Unroll 4x, interleave bytes, use pmaddubsw (all_x is small)
   506         while (count > 3) {
   507             count -= 4;
   509             int x0[4];
   510             int x1[4];
   511             __m128i all_x, sixteen_minus_x;
   512             PrepareConstantsTwoPixelPairs(xy, mask_3FFF, mask_000F,
   513                                           sixteen_8bit, mask_dist_select,
   514                                           &all_x, &sixteen_minus_x, x0, x1);
   515             xy += 4;
   517             // First pair of pixel pairs
   518             // (4x(x1, 16-x1), 4x(x0, 16-x0))
   519             __m128i scale_x;
   520             scale_x = _mm_unpacklo_epi8(sixteen_minus_x, all_x);
   522             __m128i sum0 = ProcessTwoPixelPairs<has_alpha>(
   523                 row0, row1, x0, x1,
   524                 scale_x, all_y, neg_y, alpha);
   526             // second pair of pixel pairs
   527             // (4x (x3, 16-x3), 4x (16-x2, x2))
   528             scale_x = _mm_unpackhi_epi8(sixteen_minus_x, all_x);
   530             __m128i sum1 = ProcessTwoPixelPairs<has_alpha>(
   531                 row0, row1, x0 + 2, x1 + 2,
   532                 scale_x, all_y, neg_y, alpha);
   534             // Do the final packing of the two results
   536             // Pack lower 4 16 bit values of sum into lower 4 bytes.
   537             sum0 = _mm_packus_epi16(sum0, sum1);
   539             // Extract low int and store.
   540             _mm_storeu_si128(reinterpret_cast<__m128i *>(colors), sum0);
   542             colors += 4;
   543         }
   545         // Left over.
   546         while (count-- > 0) {
   547             const uint32_t xx = *xy++;  // x0:14 | 4 | x1:14
   548             const unsigned x0 = xx >> 18;
   549             const unsigned x1 = xx & 0x3FFF;
   551             // 16x(x)
   552             const __m128i all_x = _mm_set1_epi8((xx >> 14) & 0x0F);
   554             // 16x (16-x)
   555             __m128i scale_x = _mm_sub_epi8(sixteen_8bit, all_x);
   557             // (8x (x, 16-x))
   558             scale_x = _mm_unpacklo_epi8(scale_x, all_x);
   560             // first row.
   561             __m128i sum0 = ProcessOnePixel(row0[x0], row0[x1], scale_x, neg_y);
   562             // second row.
   563             __m128i sum1 = ProcessOnePixel(row1[x0], row1[x1], scale_x, all_y);
   565             // Add both rows for full sample
   566             sum0 = _mm_add_epi16(sum0, sum1);
   568             sum0 = ScaleFourPixels<has_alpha, 8>(&sum0, alpha);
   570             // Pack lower 4 16 bit values of sum into lower 4 bytes.
   571             sum0 = _mm_packus_epi16(sum0, zero);
   573             // Extract low int and store.
   574             *colors++ = _mm_cvtsi128_si32(sum0);
   575         }
   576     }
   577 }
   579 /*
   580  * Similar to S32_generic_D32_filter_DX_SSSE3, we do not need to handle the
   581  * special case suby == 0 as suby is changing in every loop.
   582  */
   583 template<bool has_alpha>
   584 void S32_generic_D32_filter_DXDY_SSSE3(const SkBitmapProcState& s,
   585                                        const uint32_t* xy,
   586                                        int count, uint32_t* colors) {
   587     SkASSERT(count > 0 && colors != NULL);
   588     SkASSERT(s.fFilterLevel != SkPaint::kNone_FilterLevel);
   589     SkASSERT(s.fBitmap->config() == SkBitmap::kARGB_8888_Config);
   590     if (has_alpha) {
   591         SkASSERT(s.fAlphaScale < 256);
   592     } else {
   593         SkASSERT(s.fAlphaScale == 256);
   594     }
   596     const uint8_t* src_addr =
   597                         static_cast<const uint8_t*>(s.fBitmap->getPixels());
   598     const size_t rb = s.fBitmap->rowBytes();
   600     // vector constants
   601     const __m128i mask_dist_select = _mm_set_epi8(12, 12, 12, 12,
   602                                                   8,  8,  8,  8,
   603                                                   4,  4,  4,  4,
   604                                                   0,  0,  0,  0);
   605     const __m128i mask_3FFF = _mm_set1_epi32(0x3FFF);
   606     const __m128i mask_000F = _mm_set1_epi32(0x000F);
   607     const __m128i sixteen_8bit = _mm_set1_epi8(16);
   609     __m128i alpha;
   610     if (has_alpha) {
   611         // 8x(alpha)
   612         alpha = _mm_set1_epi16(s.fAlphaScale);
   613     }
   615     // Unroll 2x, interleave bytes, use pmaddubsw (all_x is small)
   616     while (count >= 2) {
   617         int xy0[4];
   618         int xy1[4];
   619         __m128i all_xy, sixteen_minus_xy;
   620         PrepareConstantsTwoPixelPairsDXDY(xy, mask_3FFF, mask_000F,
   621                                           sixteen_8bit, mask_dist_select,
   622                                          &all_xy, &sixteen_minus_xy, xy0, xy1);
   624         // (4x(x1, 16-x1), 4x(x0, 16-x0))
   625         __m128i scale_x = _mm_unpacklo_epi8(sixteen_minus_xy, all_xy);
   626         // (4x(0, y1), 4x(0, y0))
   627         __m128i all_y = _mm_unpackhi_epi8(all_xy, _mm_setzero_si128());
   628         __m128i neg_y = _mm_sub_epi16(_mm_set1_epi16(16), all_y);
   630         const uint32_t* row00 =
   631                     reinterpret_cast<const uint32_t*>(src_addr + xy0[2] * rb);
   632         const uint32_t* row01 =
   633                     reinterpret_cast<const uint32_t*>(src_addr + xy1[2] * rb);
   634         const uint32_t* row10 =
   635                     reinterpret_cast<const uint32_t*>(src_addr + xy0[3] * rb);
   636         const uint32_t* row11 =
   637                     reinterpret_cast<const uint32_t*>(src_addr + xy1[3] * rb);
   639         __m128i sum0 = ProcessTwoPixelPairsDXDY<has_alpha>(
   640                                         row00, row01, row10, row11, xy0, xy1,
   641                                         scale_x, all_y, neg_y, alpha);
   643         // Pack lower 4 16 bit values of sum into lower 4 bytes.
   644         sum0 = _mm_packus_epi16(sum0, _mm_setzero_si128());
   646         // Extract low int and store.
   647         _mm_storel_epi64(reinterpret_cast<__m128i *>(colors), sum0);
   649         xy += 4;
   650         colors += 2;
   651         count -= 2;
   652     }
   654     // Handle the remainder
   655     while (count-- > 0) {
   656         uint32_t data = *xy++;
   657         unsigned y0 = data >> 14;
   658         unsigned y1 = data & 0x3FFF;
   659         unsigned subY = y0 & 0xF;
   660         y0 >>= 4;
   662         data = *xy++;
   663         unsigned x0 = data >> 14;
   664         unsigned x1 = data & 0x3FFF;
   665         unsigned subX = x0 & 0xF;
   666         x0 >>= 4;
   668         const uint32_t* row0 =
   669                         reinterpret_cast<const uint32_t*>(src_addr + y0 * rb);
   670         const uint32_t* row1 =
   671                         reinterpret_cast<const uint32_t*>(src_addr + y1 * rb);
   673         // 16x(x)
   674         const __m128i all_x = _mm_set1_epi8(subX);
   676         // 16x (16-x)
   677         __m128i scale_x = _mm_sub_epi8(sixteen_8bit, all_x);
   679         // (8x (x, 16-x))
   680         scale_x = _mm_unpacklo_epi8(scale_x, all_x);
   682         // 8x(16)
   683         const __m128i sixteen_16bit = _mm_set1_epi16(16);
   685         // 8x (y)
   686         const __m128i all_y = _mm_set1_epi16(subY);
   688         // 8x (16-y)
   689         const __m128i neg_y = _mm_sub_epi16(sixteen_16bit, all_y);
   691         // first row.
   692         __m128i sum0 = ProcessOnePixel(row0[x0], row0[x1], scale_x, neg_y);
   693         // second row.
   694         __m128i sum1 = ProcessOnePixel(row1[x0], row1[x1], scale_x, all_y);
   696         // Add both rows for full sample
   697         sum0 = _mm_add_epi16(sum0, sum1);
   699         sum0 = ScaleFourPixels<has_alpha, 8>(&sum0, alpha);
   701         // Pack lower 4 16 bit values of sum into lower 4 bytes.
   702         sum0 = _mm_packus_epi16(sum0, _mm_setzero_si128());
   704         // Extract low int and store.
   705         *colors++ = _mm_cvtsi128_si32(sum0);
   706     }
   707 }
   708 }  // namepace
   710 void S32_opaque_D32_filter_DX_SSSE3(const SkBitmapProcState& s,
   711                                     const uint32_t* xy,
   712                                     int count, uint32_t* colors) {
   713     S32_generic_D32_filter_DX_SSSE3<false>(s, xy, count, colors);
   714 }
   716 void S32_alpha_D32_filter_DX_SSSE3(const SkBitmapProcState& s,
   717                                    const uint32_t* xy,
   718                                    int count, uint32_t* colors) {
   719     S32_generic_D32_filter_DX_SSSE3<true>(s, xy, count, colors);
   720 }
   722 void S32_opaque_D32_filter_DXDY_SSSE3(const SkBitmapProcState& s,
   723                                     const uint32_t* xy,
   724                                     int count, uint32_t* colors) {
   725     S32_generic_D32_filter_DXDY_SSSE3<false>(s, xy, count, colors);
   726 }
   728 void S32_alpha_D32_filter_DXDY_SSSE3(const SkBitmapProcState& s,
   729                                    const uint32_t* xy,
   730                                    int count, uint32_t* colors) {
   731     S32_generic_D32_filter_DXDY_SSSE3<true>(s, xy, count, colors);
   732 }
   734 #else // !defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) || SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSSE3
   736 void S32_opaque_D32_filter_DX_SSSE3(const SkBitmapProcState& s,
   737                                     const uint32_t* xy,
   738                                     int count, uint32_t* colors) {
   739     sk_throw();
   740 }
   742 void S32_alpha_D32_filter_DX_SSSE3(const SkBitmapProcState& s,
   743                                    const uint32_t* xy,
   744                                    int count, uint32_t* colors) {
   745     sk_throw();
   746 }
   748 void S32_opaque_D32_filter_DXDY_SSSE3(const SkBitmapProcState& s,
   749                                     const uint32_t* xy,
   750                                     int count, uint32_t* colors) {
   751     sk_throw();
   752 }
   754 void S32_alpha_D32_filter_DXDY_SSSE3(const SkBitmapProcState& s,
   755                                    const uint32_t* xy,
   756                                    int count, uint32_t* colors) {
   757     sk_throw();
   758 }
   760 #endif

mercurial