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

          Line data    Source code
       1             : /*
       2             :  * Copyright 2013 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 "SkMipMap.h"
       9             : #include "SkBitmap.h"
      10             : #include "SkColorPriv.h"
      11             : #include "SkHalf.h"
      12             : #include "SkMathPriv.h"
      13             : #include "SkNx.h"
      14             : #include "SkPM4fPriv.h"
      15             : #include "SkSRGB.h"
      16             : #include "SkTypes.h"
      17             : 
      18             : //
      19             : // ColorTypeFilter is the "Type" we pass to some downsample template functions.
      20             : // It controls how we expand a pixel into a large type, with space between each component,
      21             : // so we can then perform our simple filter (either box or triangle) and store the intermediates
      22             : // in the expanded type.
      23             : //
      24             : 
      25             : struct ColorTypeFilter_8888 {
      26             :     typedef uint32_t Type;
      27           0 :     static Sk4h Expand(uint32_t x) {
      28           0 :         return SkNx_cast<uint16_t>(Sk4b::Load(&x));
      29             :     }
      30           0 :     static uint32_t Compact(const Sk4h& x) {
      31             :         uint32_t r;
      32           0 :         SkNx_cast<uint8_t>(x).store(&r);
      33           0 :         return r;
      34             :     }
      35             : };
      36             : 
      37             : struct ColorTypeFilter_S32 {
      38             :     typedef uint32_t Type;
      39           0 :     static Sk4h Expand(uint32_t x) {
      40           0 :         return Sk4h(sk_linear12_from_srgb[(x      ) & 0xFF],
      41           0 :                     sk_linear12_from_srgb[(x >>  8) & 0xFF],
      42           0 :                     sk_linear12_from_srgb[(x >> 16) & 0xFF],
      43           0 :                                           (x >> 24) <<   4);
      44             :     }
      45           0 :     static uint32_t Compact(const Sk4h& x) {
      46           0 :         return sk_linear12_to_srgb[x[0]]       |
      47           0 :                sk_linear12_to_srgb[x[1]] <<  8 |
      48           0 :                sk_linear12_to_srgb[x[2]] << 16 |
      49           0 :                (x[3] >> 4)               << 24;
      50             :     }
      51             : };
      52             : 
      53             : struct ColorTypeFilter_565 {
      54             :     typedef uint16_t Type;
      55           0 :     static uint32_t Expand(uint16_t x) {
      56           0 :         return (x & ~SK_G16_MASK_IN_PLACE) | ((x & SK_G16_MASK_IN_PLACE) << 16);
      57             :     }
      58           0 :     static uint16_t Compact(uint32_t x) {
      59           0 :         return (x & ~SK_G16_MASK_IN_PLACE) | ((x >> 16) & SK_G16_MASK_IN_PLACE);
      60             :     }
      61             : };
      62             : 
      63             : struct ColorTypeFilter_4444 {
      64             :     typedef uint16_t Type;
      65           0 :     static uint32_t Expand(uint16_t x) {
      66           0 :         return (x & 0xF0F) | ((x & ~0xF0F) << 12);
      67             :     }
      68           0 :     static uint16_t Compact(uint32_t x) {
      69           0 :         return (x & 0xF0F) | ((x >> 12) & ~0xF0F);
      70             :     }
      71             : };
      72             : 
      73             : struct ColorTypeFilter_8 {
      74             :     typedef uint8_t Type;
      75           0 :     static unsigned Expand(unsigned x) {
      76           0 :         return x;
      77             :     }
      78           0 :     static uint8_t Compact(unsigned x) {
      79           0 :         return (uint8_t)x;
      80             :     }
      81             : };
      82             : 
      83             : struct ColorTypeFilter_F16 {
      84             :     typedef uint64_t Type; // SkHalf x4
      85           0 :     static Sk4f Expand(uint64_t x) {
      86           0 :         return SkHalfToFloat_finite_ftz(x);
      87             :     }
      88           0 :     static uint64_t Compact(const Sk4f& x) {
      89             :         uint64_t r;
      90           0 :         SkFloatToHalf_finite_ftz(x).store(&r);
      91           0 :         return r;
      92             :     }
      93             : };
      94             : 
      95           0 : template <typename T> T add_121(const T& a, const T& b, const T& c) {
      96           0 :     return a + b + b + c;
      97             : }
      98             : 
      99           0 : template <typename T> T shift_right(const T& x, int bits) {
     100           0 :     return x >> bits;
     101             : }
     102             : 
     103           0 : Sk4f shift_right(const Sk4f& x, int bits) {
     104           0 :     return x * (1.0f / (1 << bits));
     105             : }
     106             : 
     107           0 : template <typename T> T shift_left(const T& x, int bits) {
     108           0 :     return x << bits;
     109             : }
     110             : 
     111           0 : Sk4f shift_left(const Sk4f& x, int bits) {
     112           0 :     return x * (1 << bits);
     113             : }
     114             : 
     115             : //
     116             : //  To produce each mip level, we need to filter down by 1/2 (e.g. 100x100 -> 50,50)
     117             : //  If the starting dimension is odd, we floor the size of the lower level (e.g. 101 -> 50)
     118             : //  In those (odd) cases, we use a triangle filter, with 1-pixel overlap between samplings,
     119             : //  else for even cases, we just use a 2x box filter.
     120             : //
     121             : //  This produces 4 possible isotropic filters: 2x2 2x3 3x2 3x3 where WxH indicates the number of
     122             : //  src pixels we need to sample in each dimension to produce 1 dst pixel.
     123             : //
     124             : //  OpenGL expects a full mipmap stack to contain anisotropic space as well.
     125             : //  This means a 100x1 image would continue down to a 50x1 image, 25x1 image...
     126             : //  Because of this, we need 4 more anisotropic filters: 1x2, 1x3, 2x1, 3x1.
     127             : 
     128           0 : template <typename F> void downsample_1_2(void* dst, const void* src, size_t srcRB, int count) {
     129           0 :     SkASSERT(count > 0);
     130           0 :     auto p0 = static_cast<const typename F::Type*>(src);
     131           0 :     auto p1 = (const typename F::Type*)((const char*)p0 + srcRB);
     132           0 :     auto d = static_cast<typename F::Type*>(dst);
     133             : 
     134           0 :     for (int i = 0; i < count; ++i) {
     135           0 :         auto c00 = F::Expand(p0[0]);
     136           0 :         auto c10 = F::Expand(p1[0]);
     137             : 
     138           0 :         auto c = c00 + c10;
     139           0 :         d[i] = F::Compact(shift_right(c, 1));
     140           0 :         p0 += 2;
     141           0 :         p1 += 2;
     142             :     }
     143           0 : }
     144             : 
     145           0 : template <typename F> void downsample_1_3(void* dst, const void* src, size_t srcRB, int count) {
     146           0 :     SkASSERT(count > 0);
     147           0 :     auto p0 = static_cast<const typename F::Type*>(src);
     148           0 :     auto p1 = (const typename F::Type*)((const char*)p0 + srcRB);
     149           0 :     auto p2 = (const typename F::Type*)((const char*)p1 + srcRB);
     150           0 :     auto d = static_cast<typename F::Type*>(dst);
     151             : 
     152           0 :     for (int i = 0; i < count; ++i) {
     153           0 :         auto c00 = F::Expand(p0[0]);
     154           0 :         auto c10 = F::Expand(p1[0]);
     155           0 :         auto c20 = F::Expand(p2[0]);
     156             : 
     157           0 :         auto c = add_121(c00, c10, c20);
     158           0 :         d[i] = F::Compact(shift_right(c, 2));
     159           0 :         p0 += 2;
     160           0 :         p1 += 2;
     161           0 :         p2 += 2;
     162             :     }
     163           0 : }
     164             : 
     165           0 : template <typename F> void downsample_2_1(void* dst, const void* src, size_t srcRB, int count) {
     166           0 :     SkASSERT(count > 0);
     167           0 :     auto p0 = static_cast<const typename F::Type*>(src);
     168           0 :     auto d = static_cast<typename F::Type*>(dst);
     169             : 
     170           0 :     for (int i = 0; i < count; ++i) {
     171           0 :         auto c00 = F::Expand(p0[0]);
     172           0 :         auto c01 = F::Expand(p0[1]);
     173             : 
     174           0 :         auto c = c00 + c01;
     175           0 :         d[i] = F::Compact(shift_right(c, 1));
     176           0 :         p0 += 2;
     177             :     }
     178           0 : }
     179             : 
     180           0 : template <typename F> void downsample_2_2(void* dst, const void* src, size_t srcRB, int count) {
     181           0 :     SkASSERT(count > 0);
     182           0 :     auto p0 = static_cast<const typename F::Type*>(src);
     183           0 :     auto p1 = (const typename F::Type*)((const char*)p0 + srcRB);
     184           0 :     auto d = static_cast<typename F::Type*>(dst);
     185             : 
     186           0 :     for (int i = 0; i < count; ++i) {
     187           0 :         auto c00 = F::Expand(p0[0]);
     188           0 :         auto c01 = F::Expand(p0[1]);
     189           0 :         auto c10 = F::Expand(p1[0]);
     190           0 :         auto c11 = F::Expand(p1[1]);
     191             : 
     192           0 :         auto c = c00 + c10 + c01 + c11;
     193           0 :         d[i] = F::Compact(shift_right(c, 2));
     194           0 :         p0 += 2;
     195           0 :         p1 += 2;
     196             :     }
     197           0 : }
     198             : 
     199           0 : template <typename F> void downsample_2_3(void* dst, const void* src, size_t srcRB, int count) {
     200           0 :     SkASSERT(count > 0);
     201           0 :     auto p0 = static_cast<const typename F::Type*>(src);
     202           0 :     auto p1 = (const typename F::Type*)((const char*)p0 + srcRB);
     203           0 :     auto p2 = (const typename F::Type*)((const char*)p1 + srcRB);
     204           0 :     auto d = static_cast<typename F::Type*>(dst);
     205             : 
     206           0 :     for (int i = 0; i < count; ++i) {
     207           0 :         auto c00 = F::Expand(p0[0]);
     208           0 :         auto c01 = F::Expand(p0[1]);
     209           0 :         auto c10 = F::Expand(p1[0]);
     210           0 :         auto c11 = F::Expand(p1[1]);
     211           0 :         auto c20 = F::Expand(p2[0]);
     212           0 :         auto c21 = F::Expand(p2[1]);
     213             : 
     214           0 :         auto c = add_121(c00, c10, c20) + add_121(c01, c11, c21);
     215           0 :         d[i] = F::Compact(shift_right(c, 3));
     216           0 :         p0 += 2;
     217           0 :         p1 += 2;
     218           0 :         p2 += 2;
     219             :     }
     220           0 : }
     221             : 
     222           0 : template <typename F> void downsample_3_1(void* dst, const void* src, size_t srcRB, int count) {
     223           0 :     SkASSERT(count > 0);
     224           0 :     auto p0 = static_cast<const typename F::Type*>(src);
     225           0 :     auto d = static_cast<typename F::Type*>(dst);
     226             : 
     227           0 :     auto c02 = F::Expand(p0[0]);
     228           0 :     for (int i = 0; i < count; ++i) {
     229           0 :         auto c00 = c02;
     230           0 :         auto c01 = F::Expand(p0[1]);
     231           0 :              c02 = F::Expand(p0[2]);
     232             : 
     233           0 :         auto c = add_121(c00, c01, c02);
     234           0 :         d[i] = F::Compact(shift_right(c, 2));
     235           0 :         p0 += 2;
     236             :     }
     237           0 : }
     238             : 
     239           0 : template <typename F> void downsample_3_2(void* dst, const void* src, size_t srcRB, int count) {
     240           0 :     SkASSERT(count > 0);
     241           0 :     auto p0 = static_cast<const typename F::Type*>(src);
     242           0 :     auto p1 = (const typename F::Type*)((const char*)p0 + srcRB);
     243           0 :     auto d = static_cast<typename F::Type*>(dst);
     244             : 
     245             :     // Given pixels:
     246             :     // a0 b0 c0 d0 e0 ...
     247             :     // a1 b1 c1 d1 e1 ...
     248             :     // We want:
     249             :     // (a0 + 2*b0 + c0 + a1 + 2*b1 + c1) / 8
     250             :     // (c0 + 2*d0 + e0 + c1 + 2*d1 + e1) / 8
     251             :     // ...
     252             : 
     253           0 :     auto c0 = F::Expand(p0[0]);
     254           0 :     auto c1 = F::Expand(p1[0]);
     255           0 :     auto c = c0 + c1;
     256           0 :     for (int i = 0; i < count; ++i) {
     257           0 :         auto a = c;
     258             : 
     259           0 :         auto b0 = F::Expand(p0[1]);
     260           0 :         auto b1 = F::Expand(p1[1]);
     261           0 :         auto b = b0 + b0 + b1 + b1;
     262             : 
     263           0 :         c0 = F::Expand(p0[2]);
     264           0 :         c1 = F::Expand(p1[2]);
     265           0 :         c = c0 + c1;
     266             : 
     267           0 :         auto sum = a + b + c;
     268           0 :         d[i] = F::Compact(shift_right(sum, 3));
     269           0 :         p0 += 2;
     270           0 :         p1 += 2;
     271             :     }
     272           0 : }
     273             : 
     274           0 : template <typename F> void downsample_3_3(void* dst, const void* src, size_t srcRB, int count) {
     275           0 :     SkASSERT(count > 0);
     276           0 :     auto p0 = static_cast<const typename F::Type*>(src);
     277           0 :     auto p1 = (const typename F::Type*)((const char*)p0 + srcRB);
     278           0 :     auto p2 = (const typename F::Type*)((const char*)p1 + srcRB);
     279           0 :     auto d = static_cast<typename F::Type*>(dst);
     280             : 
     281             :     // Given pixels:
     282             :     // a0 b0 c0 d0 e0 ...
     283             :     // a1 b1 c1 d1 e1 ...
     284             :     // a2 b2 c2 d2 e2 ...
     285             :     // We want:
     286             :     // (a0 + 2*b0 + c0 + 2*a1 + 4*b1 + 2*c1 + a2 + 2*b2 + c2) / 16
     287             :     // (c0 + 2*d0 + e0 + 2*c1 + 4*d1 + 2*e1 + c2 + 2*d2 + e2) / 16
     288             :     // ...
     289             : 
     290           0 :     auto c0 = F::Expand(p0[0]);
     291           0 :     auto c1 = F::Expand(p1[0]);
     292           0 :     auto c2 = F::Expand(p2[0]);
     293           0 :     auto c = add_121(c0, c1, c2);
     294           0 :     for (int i = 0; i < count; ++i) {
     295           0 :         auto a = c;
     296             : 
     297           0 :         auto b0 = F::Expand(p0[1]);
     298           0 :         auto b1 = F::Expand(p1[1]);
     299           0 :         auto b2 = F::Expand(p2[1]);
     300           0 :         auto b = shift_left(add_121(b0, b1, b2), 1);
     301             : 
     302           0 :         c0 = F::Expand(p0[2]);
     303           0 :         c1 = F::Expand(p1[2]);
     304           0 :         c2 = F::Expand(p2[2]);
     305           0 :         c = add_121(c0, c1, c2);
     306             : 
     307           0 :         auto sum = a + b + c;
     308           0 :         d[i] = F::Compact(shift_right(sum, 4));
     309           0 :         p0 += 2;
     310           0 :         p1 += 2;
     311           0 :         p2 += 2;
     312             :     }
     313           0 : }
     314             : 
     315             : ///////////////////////////////////////////////////////////////////////////////////////////////////
     316             : 
     317             : // Some sRGB specific performance optimizations.
     318             : 
     319           0 : void downsample_2_2_srgb(void* dst, const void* src, size_t srcRB, int count) {
     320           0 :     const uint8_t* p0 = ((const uint8_t*) src);
     321           0 :     const uint8_t* p1 = ((const uint8_t*) src) + srcRB;
     322           0 :     uint8_t* d = (uint8_t*) dst;
     323             : 
     324             :     // Given pixels:
     325             :     // a0 b0 c0 d0 ...
     326             :     // a1 b1 c1 d1 ...
     327             :     // We want:
     328             :     // (a0 + b0 + a1 + b1) / 4
     329             :     // (c0 + d0 + c1 + d1) / 4
     330             :     // ...
     331           0 :     while (count >= 2) {
     332           0 :         Sk8h a0c0 = Sk8h(sk_linear12_from_srgb[p0[ 0]],
     333           0 :                          sk_linear12_from_srgb[p0[ 1]],
     334           0 :                          sk_linear12_from_srgb[p0[ 2]],
     335           0 :                          p0[ 3] << 4                  ,
     336           0 :                          sk_linear12_from_srgb[p0[ 8]],
     337           0 :                          sk_linear12_from_srgb[p0[ 9]],
     338           0 :                          sk_linear12_from_srgb[p0[10]],
     339           0 :                          p0[11] << 4                 );
     340           0 :         Sk8h b0d0 = Sk8h(sk_linear12_from_srgb[p0[ 4]],
     341           0 :                          sk_linear12_from_srgb[p0[ 5]],
     342           0 :                          sk_linear12_from_srgb[p0[ 6]],
     343           0 :                          p0[ 7] << 4                  ,
     344           0 :                          sk_linear12_from_srgb[p0[12]],
     345           0 :                          sk_linear12_from_srgb[p0[13]],
     346           0 :                          sk_linear12_from_srgb[p0[14]],
     347           0 :                          p0[15] << 4                 );
     348           0 :         Sk8h a1c1 = Sk8h(sk_linear12_from_srgb[p1[ 0]],
     349           0 :                          sk_linear12_from_srgb[p1[ 1]],
     350           0 :                          sk_linear12_from_srgb[p1[ 2]],
     351           0 :                          p1[ 3] << 4                  ,
     352           0 :                          sk_linear12_from_srgb[p1[ 8]],
     353           0 :                          sk_linear12_from_srgb[p1[ 9]],
     354           0 :                          sk_linear12_from_srgb[p1[10]],
     355           0 :                          p1[11] << 4                 );
     356           0 :         Sk8h b1d1 = Sk8h(sk_linear12_from_srgb[p1[ 4]],
     357           0 :                          sk_linear12_from_srgb[p1[ 5]],
     358           0 :                          sk_linear12_from_srgb[p1[ 6]],
     359           0 :                          p1[ 7] << 4                  ,
     360           0 :                          sk_linear12_from_srgb[p1[12]],
     361           0 :                          sk_linear12_from_srgb[p1[13]],
     362           0 :                          sk_linear12_from_srgb[p1[14]],
     363           0 :                          p1[15] << 4                 );
     364             : 
     365           0 :         Sk8h avg = (a0c0 + b0d0 + a1c1 + b1d1) >> 2;
     366           0 :         d[0] = sk_linear12_to_srgb[avg[0]];
     367           0 :         d[1] = sk_linear12_to_srgb[avg[1]];
     368           0 :         d[2] = sk_linear12_to_srgb[avg[2]];
     369           0 :         d[3] = avg[3] >> 4;
     370           0 :         d[4] = sk_linear12_to_srgb[avg[4]];
     371           0 :         d[5] = sk_linear12_to_srgb[avg[5]];
     372           0 :         d[6] = sk_linear12_to_srgb[avg[6]];
     373           0 :         d[7] = avg[7] >> 4;
     374             : 
     375           0 :         p0 += 16;
     376           0 :         p1 += 16;
     377           0 :         d += 8;
     378           0 :         count -= 2;
     379             :     }
     380             : 
     381           0 :     if (count) {
     382           0 :         downsample_2_2<ColorTypeFilter_S32>(d, p0, srcRB, count);
     383             :     }
     384           0 : }
     385             : 
     386           0 : void downsample_2_3_srgb(void* dst, const void* src, size_t srcRB, int count) {
     387           0 :     const uint8_t* p0 = ((const uint8_t*) src);
     388           0 :     const uint8_t* p1 = p0 + srcRB;
     389           0 :     const uint8_t* p2 = p1 + srcRB;
     390           0 :     uint8_t* d = (uint8_t*) dst;
     391             : 
     392             :     // Given pixels:
     393             :     // a0 b0 c0 d0 ...
     394             :     // a1 b1 c1 d1 ...
     395             :     // a2 b2 c2 d2 ...
     396             :     // We want:
     397             :     // (a0 + b0 + 2*a1 + 2*b1 + a2 + b2) / 8
     398             :     // (c0 + d0 + 2*c1 + 2*d1 + c2 + d2) / 8
     399             :     // ...
     400           0 :     while (count >= 2) {
     401           0 :         Sk8h a0c0 = Sk8h(sk_linear12_from_srgb[p0[ 0]],
     402           0 :                          sk_linear12_from_srgb[p0[ 1]],
     403           0 :                          sk_linear12_from_srgb[p0[ 2]],
     404           0 :                          p0[ 3] << 4                  ,
     405           0 :                          sk_linear12_from_srgb[p0[ 8]],
     406           0 :                          sk_linear12_from_srgb[p0[ 9]],
     407           0 :                          sk_linear12_from_srgb[p0[10]],
     408           0 :                          p0[11] << 4                 );
     409           0 :         Sk8h b0d0 = Sk8h(sk_linear12_from_srgb[p0[ 4]],
     410           0 :                          sk_linear12_from_srgb[p0[ 5]],
     411           0 :                          sk_linear12_from_srgb[p0[ 6]],
     412           0 :                          p0[ 7] << 4                  ,
     413           0 :                          sk_linear12_from_srgb[p0[12]],
     414           0 :                          sk_linear12_from_srgb[p0[13]],
     415           0 :                          sk_linear12_from_srgb[p0[14]],
     416           0 :                          p0[15] << 4                 );
     417           0 :         Sk8h a1c1 = Sk8h(sk_linear12_from_srgb[p1[ 0]],
     418           0 :                          sk_linear12_from_srgb[p1[ 1]],
     419           0 :                          sk_linear12_from_srgb[p1[ 2]],
     420           0 :                          p1[ 3] << 4                  ,
     421           0 :                          sk_linear12_from_srgb[p1[ 8]],
     422           0 :                          sk_linear12_from_srgb[p1[ 9]],
     423           0 :                          sk_linear12_from_srgb[p1[10]],
     424           0 :                          p1[11] << 4                 );
     425           0 :         Sk8h b1d1 = Sk8h(sk_linear12_from_srgb[p1[ 4]],
     426           0 :                          sk_linear12_from_srgb[p1[ 5]],
     427           0 :                          sk_linear12_from_srgb[p1[ 6]],
     428           0 :                          p1[ 7] << 4                  ,
     429           0 :                          sk_linear12_from_srgb[p1[12]],
     430           0 :                          sk_linear12_from_srgb[p1[13]],
     431           0 :                          sk_linear12_from_srgb[p1[14]],
     432           0 :                          p1[15] << 4                 );
     433           0 :         Sk8h a2c2 = Sk8h(sk_linear12_from_srgb[p2[ 0]],
     434           0 :                          sk_linear12_from_srgb[p2[ 1]],
     435           0 :                          sk_linear12_from_srgb[p2[ 2]],
     436           0 :                          p2[ 3] << 4                  ,
     437           0 :                          sk_linear12_from_srgb[p2[ 8]],
     438           0 :                          sk_linear12_from_srgb[p2[ 9]],
     439           0 :                          sk_linear12_from_srgb[p2[10]],
     440           0 :                          p2[11] << 4                 );
     441           0 :         Sk8h b2d2 = Sk8h(sk_linear12_from_srgb[p2[ 4]],
     442           0 :                          sk_linear12_from_srgb[p2[ 5]],
     443           0 :                          sk_linear12_from_srgb[p2[ 6]],
     444           0 :                          p2[ 7] << 4                  ,
     445           0 :                          sk_linear12_from_srgb[p2[12]],
     446           0 :                          sk_linear12_from_srgb[p2[13]],
     447           0 :                          sk_linear12_from_srgb[p2[14]],
     448           0 :                          p2[15] << 4                 );
     449             : 
     450           0 :         Sk8h avg = (a0c0 + b0d0 + a1c1 + a1c1 + b1d1 + b1d1 + a2c2 + b2d2) >> 3;
     451           0 :         d[0] = sk_linear12_to_srgb[avg[0]];
     452           0 :         d[1] = sk_linear12_to_srgb[avg[1]];
     453           0 :         d[2] = sk_linear12_to_srgb[avg[2]];
     454           0 :         d[3] = avg[3] >> 4;
     455           0 :         d[4] = sk_linear12_to_srgb[avg[4]];
     456           0 :         d[5] = sk_linear12_to_srgb[avg[5]];
     457           0 :         d[6] = sk_linear12_to_srgb[avg[6]];
     458           0 :         d[7] = avg[7] >> 4;
     459             : 
     460           0 :         p0 += 16;
     461           0 :         p1 += 16;
     462           0 :         p2 += 16;
     463           0 :         d += 8;
     464           0 :         count -= 2;
     465             :     }
     466             : 
     467           0 :     if (count) {
     468           0 :         downsample_2_3<ColorTypeFilter_S32>(d, p0, srcRB, count);
     469             :     }
     470           0 : }
     471             : 
     472             : ///////////////////////////////////////////////////////////////////////////////////////////////////
     473             : 
     474           0 : size_t SkMipMap::AllocLevelsSize(int levelCount, size_t pixelSize) {
     475           0 :     if (levelCount < 0) {
     476           0 :         return 0;
     477             :     }
     478           0 :     int64_t size = sk_64_mul(levelCount + 1, sizeof(Level)) + pixelSize;
     479           0 :     if (!sk_64_isS32(size)) {
     480           0 :         return 0;
     481             :     }
     482           0 :     return sk_64_asS32(size);
     483             : }
     484             : 
     485           0 : SkMipMap* SkMipMap::Build(const SkPixmap& src, SkDestinationSurfaceColorMode colorMode,
     486             :                           SkDiscardableFactoryProc fact) {
     487             :     typedef void FilterProc(void*, const void* srcPtr, size_t srcRB, int count);
     488             : 
     489           0 :     FilterProc* proc_1_2 = nullptr;
     490           0 :     FilterProc* proc_1_3 = nullptr;
     491           0 :     FilterProc* proc_2_1 = nullptr;
     492           0 :     FilterProc* proc_2_2 = nullptr;
     493           0 :     FilterProc* proc_2_3 = nullptr;
     494           0 :     FilterProc* proc_3_1 = nullptr;
     495           0 :     FilterProc* proc_3_2 = nullptr;
     496           0 :     FilterProc* proc_3_3 = nullptr;
     497             : 
     498           0 :     const SkColorType ct = src.colorType();
     499           0 :     const SkAlphaType at = src.alphaType();
     500             :     const bool srgbGamma = (SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware == colorMode)
     501           0 :                             && src.info().gammaCloseToSRGB();
     502             : 
     503           0 :     switch (ct) {
     504             :         case kRGBA_8888_SkColorType:
     505             :         case kBGRA_8888_SkColorType:
     506           0 :             if (srgbGamma) {
     507           0 :                 proc_1_2 = downsample_1_2<ColorTypeFilter_S32>;
     508           0 :                 proc_1_3 = downsample_1_3<ColorTypeFilter_S32>;
     509           0 :                 proc_2_1 = downsample_2_1<ColorTypeFilter_S32>;
     510           0 :                 proc_2_2 = downsample_2_2_srgb;
     511           0 :                 proc_2_3 = downsample_2_3_srgb;
     512           0 :                 proc_3_1 = downsample_3_1<ColorTypeFilter_S32>;
     513           0 :                 proc_3_2 = downsample_3_2<ColorTypeFilter_S32>;
     514           0 :                 proc_3_3 = downsample_3_3<ColorTypeFilter_S32>;
     515             :             } else {
     516           0 :                 proc_1_2 = downsample_1_2<ColorTypeFilter_8888>;
     517           0 :                 proc_1_3 = downsample_1_3<ColorTypeFilter_8888>;
     518           0 :                 proc_2_1 = downsample_2_1<ColorTypeFilter_8888>;
     519           0 :                 proc_2_2 = downsample_2_2<ColorTypeFilter_8888>;
     520           0 :                 proc_2_3 = downsample_2_3<ColorTypeFilter_8888>;
     521           0 :                 proc_3_1 = downsample_3_1<ColorTypeFilter_8888>;
     522           0 :                 proc_3_2 = downsample_3_2<ColorTypeFilter_8888>;
     523           0 :                 proc_3_3 = downsample_3_3<ColorTypeFilter_8888>;
     524             :             }
     525           0 :             break;
     526             :         case kRGB_565_SkColorType:
     527           0 :             proc_1_2 = downsample_1_2<ColorTypeFilter_565>;
     528           0 :             proc_1_3 = downsample_1_3<ColorTypeFilter_565>;
     529           0 :             proc_2_1 = downsample_2_1<ColorTypeFilter_565>;
     530           0 :             proc_2_2 = downsample_2_2<ColorTypeFilter_565>;
     531           0 :             proc_2_3 = downsample_2_3<ColorTypeFilter_565>;
     532           0 :             proc_3_1 = downsample_3_1<ColorTypeFilter_565>;
     533           0 :             proc_3_2 = downsample_3_2<ColorTypeFilter_565>;
     534           0 :             proc_3_3 = downsample_3_3<ColorTypeFilter_565>;
     535           0 :             break;
     536             :         case kARGB_4444_SkColorType:
     537           0 :             proc_1_2 = downsample_1_2<ColorTypeFilter_4444>;
     538           0 :             proc_1_3 = downsample_1_3<ColorTypeFilter_4444>;
     539           0 :             proc_2_1 = downsample_2_1<ColorTypeFilter_4444>;
     540           0 :             proc_2_2 = downsample_2_2<ColorTypeFilter_4444>;
     541           0 :             proc_2_3 = downsample_2_3<ColorTypeFilter_4444>;
     542           0 :             proc_3_1 = downsample_3_1<ColorTypeFilter_4444>;
     543           0 :             proc_3_2 = downsample_3_2<ColorTypeFilter_4444>;
     544           0 :             proc_3_3 = downsample_3_3<ColorTypeFilter_4444>;
     545           0 :             break;
     546             :         case kAlpha_8_SkColorType:
     547             :         case kGray_8_SkColorType:
     548           0 :             proc_1_2 = downsample_1_2<ColorTypeFilter_8>;
     549           0 :             proc_1_3 = downsample_1_3<ColorTypeFilter_8>;
     550           0 :             proc_2_1 = downsample_2_1<ColorTypeFilter_8>;
     551           0 :             proc_2_2 = downsample_2_2<ColorTypeFilter_8>;
     552           0 :             proc_2_3 = downsample_2_3<ColorTypeFilter_8>;
     553           0 :             proc_3_1 = downsample_3_1<ColorTypeFilter_8>;
     554           0 :             proc_3_2 = downsample_3_2<ColorTypeFilter_8>;
     555           0 :             proc_3_3 = downsample_3_3<ColorTypeFilter_8>;
     556           0 :             break;
     557             :         case kRGBA_F16_SkColorType:
     558           0 :             proc_1_2 = downsample_1_2<ColorTypeFilter_F16>;
     559           0 :             proc_1_3 = downsample_1_3<ColorTypeFilter_F16>;
     560           0 :             proc_2_1 = downsample_2_1<ColorTypeFilter_F16>;
     561           0 :             proc_2_2 = downsample_2_2<ColorTypeFilter_F16>;
     562           0 :             proc_2_3 = downsample_2_3<ColorTypeFilter_F16>;
     563           0 :             proc_3_1 = downsample_3_1<ColorTypeFilter_F16>;
     564           0 :             proc_3_2 = downsample_3_2<ColorTypeFilter_F16>;
     565           0 :             proc_3_3 = downsample_3_3<ColorTypeFilter_F16>;
     566           0 :             break;
     567             :         default:
     568             :             // TODO: We could build miplevels for kIndex8 if the levels were in 8888.
     569             :             //       Means using more ram, but the quality would be fine.
     570           0 :             return nullptr;
     571             :     }
     572             : 
     573           0 :     if (src.width() <= 1 && src.height() <= 1) {
     574           0 :         return nullptr;
     575             :     }
     576             :     // whip through our loop to compute the exact size needed
     577           0 :     size_t size = 0;
     578           0 :     int countLevels = ComputeLevelCount(src.width(), src.height());
     579           0 :     for (int currentMipLevel = countLevels; currentMipLevel >= 0; currentMipLevel--) {
     580           0 :         SkISize mipSize = ComputeLevelSize(src.width(), src.height(), currentMipLevel);
     581           0 :         size += SkColorTypeMinRowBytes(ct, mipSize.fWidth) * mipSize.fHeight;
     582             :     }
     583             : 
     584           0 :     size_t storageSize = SkMipMap::AllocLevelsSize(countLevels, size);
     585           0 :     if (0 == storageSize) {
     586           0 :         return nullptr;
     587             :     }
     588             : 
     589             :     SkMipMap* mipmap;
     590           0 :     if (fact) {
     591           0 :         SkDiscardableMemory* dm = fact(storageSize);
     592           0 :         if (nullptr == dm) {
     593           0 :             return nullptr;
     594             :         }
     595           0 :         mipmap = new SkMipMap(storageSize, dm);
     596             :     } else {
     597           0 :         mipmap = new SkMipMap(sk_malloc_throw(storageSize), storageSize);
     598             :     }
     599             : 
     600             :     // init
     601           0 :     mipmap->fCS = sk_ref_sp(src.info().colorSpace());
     602           0 :     mipmap->fCount = countLevels;
     603           0 :     mipmap->fLevels = (Level*)mipmap->writable_data();
     604           0 :     SkASSERT(mipmap->fLevels);
     605             : 
     606           0 :     Level* levels = mipmap->fLevels;
     607           0 :     uint8_t*    baseAddr = (uint8_t*)&levels[countLevels];
     608           0 :     uint8_t*    addr = baseAddr;
     609           0 :     int         width = src.width();
     610           0 :     int         height = src.height();
     611             :     uint32_t    rowBytes;
     612           0 :     SkPixmap    srcPM(src);
     613             : 
     614           0 :     for (int i = 0; i < countLevels; ++i) {
     615             :         FilterProc* proc;
     616           0 :         if (height & 1) {
     617           0 :             if (height == 1) {        // src-height is 1
     618           0 :                 if (width & 1) {      // src-width is 3
     619           0 :                     proc = proc_3_1;
     620             :                 } else {              // src-width is 2
     621           0 :                     proc = proc_2_1;
     622             :                 }
     623             :             } else {                  // src-height is 3
     624           0 :                 if (width & 1) {
     625           0 :                     if (width == 1) { // src-width is 1
     626           0 :                         proc = proc_1_3;
     627             :                     } else {          // src-width is 3
     628           0 :                         proc = proc_3_3;
     629             :                     }
     630             :                 } else {              // src-width is 2
     631           0 :                     proc = proc_2_3;
     632             :                 }
     633             :             }
     634             :         } else {                      // src-height is 2
     635           0 :             if (width & 1) {
     636           0 :                 if (width == 1) {     // src-width is 1
     637           0 :                     proc = proc_1_2;
     638             :                 } else {              // src-width is 3
     639           0 :                     proc = proc_3_2;
     640             :                 }
     641             :             } else {                  // src-width is 2
     642           0 :                 proc = proc_2_2;
     643             :             }
     644             :         }
     645           0 :         width = SkTMax(1, width >> 1);
     646           0 :         height = SkTMax(1, height >> 1);
     647           0 :         rowBytes = SkToU32(SkColorTypeMinRowBytes(ct, width));
     648             : 
     649             :         // We make the Info w/o any colorspace, since that storage is not under our control, and
     650             :         // will not be deleted in a controlled fashion. When the caller is given the pixmap for
     651             :         // a given level, we augment this pixmap with fCS (which we do manage).
     652           0 :         new (&levels[i].fPixmap) SkPixmap(SkImageInfo::Make(width, height, ct, at), addr, rowBytes);
     653           0 :         levels[i].fScale  = SkSize::Make(SkIntToScalar(width)  / src.width(),
     654           0 :                                          SkIntToScalar(height) / src.height());
     655             : 
     656           0 :         const SkPixmap& dstPM = levels[i].fPixmap;
     657           0 :         const void* srcBasePtr = srcPM.addr();
     658           0 :         void* dstBasePtr = dstPM.writable_addr();
     659             : 
     660           0 :         const size_t srcRB = srcPM.rowBytes();
     661           0 :         for (int y = 0; y < height; y++) {
     662           0 :             proc(dstBasePtr, srcBasePtr, srcRB, width);
     663           0 :             srcBasePtr = (char*)srcBasePtr + srcRB * 2; // jump two rows
     664           0 :             dstBasePtr = (char*)dstBasePtr + dstPM.rowBytes();
     665             :         }
     666           0 :         srcPM = dstPM;
     667           0 :         addr += height * rowBytes;
     668             :     }
     669           0 :     SkASSERT(addr == baseAddr + size);
     670             : 
     671           0 :     SkASSERT(mipmap->fLevels);
     672           0 :     return mipmap;
     673             : }
     674             : 
     675           0 : int SkMipMap::ComputeLevelCount(int baseWidth, int baseHeight) {
     676           0 :     if (baseWidth < 1 || baseHeight < 1) {
     677           0 :         return 0;
     678             :     }
     679             : 
     680             :     // OpenGL's spec requires that each mipmap level have height/width equal to
     681             :     // max(1, floor(original_height / 2^i)
     682             :     // (or original_width) where i is the mipmap level.
     683             :     // Continue scaling down until both axes are size 1.
     684             : 
     685           0 :     const int largestAxis = SkTMax(baseWidth, baseHeight);
     686           0 :     if (largestAxis < 2) {
     687             :         // SkMipMap::Build requires a minimum size of 2.
     688           0 :         return 0;
     689             :     }
     690           0 :     const int leadingZeros = SkCLZ(static_cast<uint32_t>(largestAxis));
     691             :     // If the value 00011010 has 3 leading 0s then it has 5 significant bits
     692             :     // (the bits which are not leading zeros)
     693           0 :     const int significantBits = (sizeof(uint32_t) * 8) - leadingZeros;
     694             :     // This is making the assumption that the size of a byte is 8 bits
     695             :     // and that sizeof(uint32_t)'s implementation-defined behavior is 4.
     696           0 :     int mipLevelCount = significantBits;
     697             : 
     698             :     // SkMipMap does not include the base mip level.
     699             :     // For example, it contains levels 1-x instead of 0-x.
     700             :     // This is because the image used to create SkMipMap is the base level.
     701             :     // So subtract 1 from the mip level count.
     702           0 :     if (mipLevelCount > 0) {
     703           0 :         --mipLevelCount;
     704             :     }
     705             : 
     706           0 :     return mipLevelCount;
     707             : }
     708             : 
     709           0 : SkISize SkMipMap::ComputeLevelSize(int baseWidth, int baseHeight, int level) {
     710           0 :     if (baseWidth < 1 || baseHeight < 1) {
     711           0 :         return SkISize::Make(0, 0);
     712             :     }
     713             : 
     714           0 :     int maxLevelCount = ComputeLevelCount(baseWidth, baseHeight);
     715           0 :     if (level >= maxLevelCount || level < 0) {
     716           0 :         return SkISize::Make(0, 0);
     717             :     }
     718             :     // OpenGL's spec requires that each mipmap level have height/width equal to
     719             :     // max(1, floor(original_height / 2^i)
     720             :     // (or original_width) where i is the mipmap level.
     721             : 
     722             :     // SkMipMap does not include the base mip level.
     723             :     // For example, it contains levels 1-x instead of 0-x.
     724             :     // This is because the image used to create SkMipMap is the base level.
     725             :     // So subtract 1 from the mip level to get the index stored by SkMipMap.
     726           0 :     int width = SkTMax(1, baseWidth >> (level + 1));
     727           0 :     int height = SkTMax(1, baseHeight >> (level + 1));
     728             : 
     729           0 :     return SkISize::Make(width, height);
     730             : }
     731             : 
     732             : ///////////////////////////////////////////////////////////////////////////////
     733             : 
     734           0 : bool SkMipMap::extractLevel(const SkSize& scaleSize, Level* levelPtr) const {
     735           0 :     if (nullptr == fLevels) {
     736           0 :         return false;
     737             :     }
     738             : 
     739           0 :     SkASSERT(scaleSize.width() >= 0 && scaleSize.height() >= 0);
     740             : 
     741             : #ifndef SK_SUPPORT_LEGACY_ANISOTROPIC_MIPMAP_SCALE
     742             :     // Use the smallest scale to match the GPU impl.
     743           0 :     const SkScalar scale = SkTMin(scaleSize.width(), scaleSize.height());
     744             : #else
     745             :     // Ideally we'd pick the smaller scale, to match Ganesh.  But ignoring one of the
     746             :     // scales can produce some atrocious results, so for now we use the geometric mean.
     747             :     // (https://bugs.chromium.org/p/skia/issues/detail?id=4863)
     748             :     const SkScalar scale = SkScalarSqrt(scaleSize.width() * scaleSize.height());
     749             : #endif
     750             : 
     751           0 :     if (scale >= SK_Scalar1 || scale <= 0 || !SkScalarIsFinite(scale)) {
     752           0 :         return false;
     753             :     }
     754             : 
     755           0 :     SkScalar L = -SkScalarLog2(scale);
     756           0 :     if (!SkScalarIsFinite(L)) {
     757           0 :         return false;
     758             :     }
     759           0 :     SkASSERT(L >= 0);
     760           0 :     int level = SkScalarFloorToInt(L);
     761             : 
     762           0 :     SkASSERT(level >= 0);
     763           0 :     if (level <= 0) {
     764           0 :         return false;
     765             :     }
     766             : 
     767           0 :     if (level > fCount) {
     768           0 :         level = fCount;
     769             :     }
     770           0 :     if (levelPtr) {
     771           0 :         *levelPtr = fLevels[level - 1];
     772             :         // need to augment with our colorspace
     773           0 :         levelPtr->fPixmap.setColorSpace(fCS);
     774             :     }
     775           0 :     return true;
     776             : }
     777             : 
     778             : // Helper which extracts a pixmap from the src bitmap
     779             : //
     780           0 : SkMipMap* SkMipMap::Build(const SkBitmap& src, SkDestinationSurfaceColorMode colorMode,
     781             :                           SkDiscardableFactoryProc fact) {
     782           0 :     SkAutoPixmapUnlock srcUnlocker;
     783           0 :     if (!src.requestLock(&srcUnlocker)) {
     784           0 :         return nullptr;
     785             :     }
     786           0 :     const SkPixmap& srcPixmap = srcUnlocker.pixmap();
     787             :     // Try to catch where we might have returned nullptr for src crbug.com/492818
     788           0 :     if (nullptr == srcPixmap.addr()) {
     789           0 :         sk_throw();
     790             :     }
     791           0 :     return Build(srcPixmap, colorMode, fact);
     792             : }
     793             : 
     794           0 : int SkMipMap::countLevels() const {
     795           0 :     return fCount;
     796             : }
     797             : 
     798           0 : bool SkMipMap::getLevel(int index, Level* levelPtr) const {
     799           0 :     if (NULL == fLevels) {
     800           0 :         return false;
     801             :     }
     802           0 :     if (index < 0) {
     803           0 :         return false;
     804             :     }
     805           0 :     if (index > fCount - 1) {
     806           0 :         return false;
     807             :     }
     808           0 :     if (levelPtr) {
     809           0 :         *levelPtr = fLevels[index];
     810             :     }
     811           0 :     return true;
     812             : }

Generated by: LCOV version 1.13