LCOV - code coverage report
Current view: top level - media/libyuv/libyuv/source - scale_argb.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 254 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 11 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  *  Copyright 2011 The LibYuv Project Authors. All rights reserved.
       3             :  *
       4             :  *  Use of this source code is governed by a BSD-style license
       5             :  *  that can be found in the LICENSE file in the root of the source
       6             :  *  tree. An additional intellectual property rights grant can be found
       7             :  *  in the file PATENTS. All contributing project authors may
       8             :  *  be found in the AUTHORS file in the root of the source tree.
       9             :  */
      10             : 
      11             : #include "libyuv/scale.h"
      12             : 
      13             : #include <assert.h>
      14             : #include <string.h>
      15             : 
      16             : #include "libyuv/cpu_id.h"
      17             : #include "libyuv/planar_functions.h"  // For CopyARGB
      18             : #include "libyuv/row.h"
      19             : #include "libyuv/scale_row.h"
      20             : 
      21             : #ifdef __cplusplus
      22             : namespace libyuv {
      23             : extern "C" {
      24             : #endif
      25             : 
      26           0 : static __inline int Abs(int v) {
      27           0 :   return v >= 0 ? v : -v;
      28             : }
      29             : 
      30             : // ScaleARGB ARGB, 1/2
      31             : // This is an optimized version for scaling down a ARGB to 1/2 of
      32             : // its original size.
      33           0 : static void ScaleARGBDown2(int src_width,
      34             :                            int src_height,
      35             :                            int dst_width,
      36             :                            int dst_height,
      37             :                            int src_stride,
      38             :                            int dst_stride,
      39             :                            const uint8* src_argb,
      40             :                            uint8* dst_argb,
      41             :                            int x,
      42             :                            int dx,
      43             :                            int y,
      44             :                            int dy,
      45             :                            enum FilterMode filtering) {
      46             :   int j;
      47           0 :   int row_stride = src_stride * (dy >> 16);
      48             :   void (*ScaleARGBRowDown2)(const uint8* src_argb, ptrdiff_t src_stride,
      49             :                             uint8* dst_argb, int dst_width) =
      50             :       filtering == kFilterNone
      51           0 :           ? ScaleARGBRowDown2_C
      52           0 :           : (filtering == kFilterLinear ? ScaleARGBRowDown2Linear_C
      53           0 :                                         : ScaleARGBRowDown2Box_C);
      54             :   (void)src_width;
      55             :   (void)src_height;
      56             :   (void)dx;
      57           0 :   assert(dx == 65536 * 2);      // Test scale factor of 2.
      58           0 :   assert((dy & 0x1ffff) == 0);  // Test vertical scale is multiple of 2.
      59             :   // Advance to odd row, even column.
      60           0 :   if (filtering == kFilterBilinear) {
      61           0 :     src_argb += (y >> 16) * src_stride + (x >> 16) * 4;
      62             :   } else {
      63           0 :     src_argb += (y >> 16) * src_stride + ((x >> 16) - 1) * 4;
      64             :   }
      65             : 
      66             : #if defined(HAS_SCALEARGBROWDOWN2_SSE2)
      67           0 :   if (TestCpuFlag(kCpuHasSSE2)) {
      68           0 :     ScaleARGBRowDown2 =
      69             :         filtering == kFilterNone
      70           0 :             ? ScaleARGBRowDown2_Any_SSE2
      71           0 :             : (filtering == kFilterLinear ? ScaleARGBRowDown2Linear_Any_SSE2
      72             :                                           : ScaleARGBRowDown2Box_Any_SSE2);
      73           0 :     if (IS_ALIGNED(dst_width, 4)) {
      74           0 :       ScaleARGBRowDown2 =
      75             :           filtering == kFilterNone
      76           0 :               ? ScaleARGBRowDown2_SSE2
      77           0 :               : (filtering == kFilterLinear ? ScaleARGBRowDown2Linear_SSE2
      78             :                                             : ScaleARGBRowDown2Box_SSE2);
      79             :     }
      80             :   }
      81             : #endif
      82             : #if defined(HAS_SCALEARGBROWDOWN2_NEON)
      83             :   if (TestCpuFlag(kCpuHasNEON)) {
      84             :     ScaleARGBRowDown2 =
      85             :         filtering == kFilterNone
      86             :             ? ScaleARGBRowDown2_Any_NEON
      87             :             : (filtering == kFilterLinear ? ScaleARGBRowDown2Linear_Any_NEON
      88             :                                           : ScaleARGBRowDown2Box_Any_NEON);
      89             :     if (IS_ALIGNED(dst_width, 8)) {
      90             :       ScaleARGBRowDown2 =
      91             :           filtering == kFilterNone
      92             :               ? ScaleARGBRowDown2_NEON
      93             :               : (filtering == kFilterLinear ? ScaleARGBRowDown2Linear_NEON
      94             :                                             : ScaleARGBRowDown2Box_NEON);
      95             :     }
      96             :   }
      97             : #endif
      98             : #if defined(HAS_SCALEARGBROWDOWN2_MSA)
      99             :   if (TestCpuFlag(kCpuHasMSA)) {
     100             :     ScaleARGBRowDown2 =
     101             :         filtering == kFilterNone
     102             :             ? ScaleARGBRowDown2_Any_MSA
     103             :             : (filtering == kFilterLinear ? ScaleARGBRowDown2Linear_Any_MSA
     104             :                                           : ScaleARGBRowDown2Box_Any_MSA);
     105             :     if (IS_ALIGNED(dst_width, 4)) {
     106             :       ScaleARGBRowDown2 =
     107             :           filtering == kFilterNone
     108             :               ? ScaleARGBRowDown2_MSA
     109             :               : (filtering == kFilterLinear ? ScaleARGBRowDown2Linear_MSA
     110             :                                             : ScaleARGBRowDown2Box_MSA);
     111             :     }
     112             :   }
     113             : #endif
     114             : 
     115           0 :   if (filtering == kFilterLinear) {
     116           0 :     src_stride = 0;
     117             :   }
     118           0 :   for (j = 0; j < dst_height; ++j) {
     119           0 :     ScaleARGBRowDown2(src_argb, src_stride, dst_argb, dst_width);
     120           0 :     src_argb += row_stride;
     121           0 :     dst_argb += dst_stride;
     122             :   }
     123           0 : }
     124             : 
     125             : // ScaleARGB ARGB, 1/4
     126             : // This is an optimized version for scaling down a ARGB to 1/4 of
     127             : // its original size.
     128           0 : static void ScaleARGBDown4Box(int src_width,
     129             :                               int src_height,
     130             :                               int dst_width,
     131             :                               int dst_height,
     132             :                               int src_stride,
     133             :                               int dst_stride,
     134             :                               const uint8* src_argb,
     135             :                               uint8* dst_argb,
     136             :                               int x,
     137             :                               int dx,
     138             :                               int y,
     139             :                               int dy) {
     140             :   int j;
     141             :   // Allocate 2 rows of ARGB.
     142           0 :   const int kRowSize = (dst_width * 2 * 4 + 31) & ~31;
     143           0 :   align_buffer_64(row, kRowSize * 2);
     144           0 :   int row_stride = src_stride * (dy >> 16);
     145             :   void (*ScaleARGBRowDown2)(const uint8* src_argb, ptrdiff_t src_stride,
     146             :                             uint8* dst_argb, int dst_width) =
     147           0 :       ScaleARGBRowDown2Box_C;
     148             :   // Advance to odd row, even column.
     149           0 :   src_argb += (y >> 16) * src_stride + (x >> 16) * 4;
     150             :   (void)src_width;
     151             :   (void)src_height;
     152             :   (void)dx;
     153           0 :   assert(dx == 65536 * 4);      // Test scale factor of 4.
     154           0 :   assert((dy & 0x3ffff) == 0);  // Test vertical scale is multiple of 4.
     155             : #if defined(HAS_SCALEARGBROWDOWN2_SSE2)
     156           0 :   if (TestCpuFlag(kCpuHasSSE2)) {
     157           0 :     ScaleARGBRowDown2 = ScaleARGBRowDown2Box_Any_SSE2;
     158           0 :     if (IS_ALIGNED(dst_width, 4)) {
     159           0 :       ScaleARGBRowDown2 = ScaleARGBRowDown2Box_SSE2;
     160             :     }
     161             :   }
     162             : #endif
     163             : #if defined(HAS_SCALEARGBROWDOWN2_NEON)
     164             :   if (TestCpuFlag(kCpuHasNEON)) {
     165             :     ScaleARGBRowDown2 = ScaleARGBRowDown2Box_Any_NEON;
     166             :     if (IS_ALIGNED(dst_width, 8)) {
     167             :       ScaleARGBRowDown2 = ScaleARGBRowDown2Box_NEON;
     168             :     }
     169             :   }
     170             : #endif
     171             : 
     172           0 :   for (j = 0; j < dst_height; ++j) {
     173           0 :     ScaleARGBRowDown2(src_argb, src_stride, row, dst_width * 2);
     174           0 :     ScaleARGBRowDown2(src_argb + src_stride * 2, src_stride, row + kRowSize,
     175           0 :                       dst_width * 2);
     176           0 :     ScaleARGBRowDown2(row, kRowSize, dst_argb, dst_width);
     177           0 :     src_argb += row_stride;
     178           0 :     dst_argb += dst_stride;
     179             :   }
     180           0 :   free_aligned_buffer_64(row);
     181           0 : }
     182             : 
     183             : // ScaleARGB ARGB Even
     184             : // This is an optimized version for scaling down a ARGB to even
     185             : // multiple of its original size.
     186           0 : static void ScaleARGBDownEven(int src_width,
     187             :                               int src_height,
     188             :                               int dst_width,
     189             :                               int dst_height,
     190             :                               int src_stride,
     191             :                               int dst_stride,
     192             :                               const uint8* src_argb,
     193             :                               uint8* dst_argb,
     194             :                               int x,
     195             :                               int dx,
     196             :                               int y,
     197             :                               int dy,
     198             :                               enum FilterMode filtering) {
     199             :   int j;
     200           0 :   int col_step = dx >> 16;
     201           0 :   int row_stride = (dy >> 16) * src_stride;
     202             :   void (*ScaleARGBRowDownEven)(const uint8* src_argb, ptrdiff_t src_stride,
     203             :                                int src_step, uint8* dst_argb, int dst_width) =
     204           0 :       filtering ? ScaleARGBRowDownEvenBox_C : ScaleARGBRowDownEven_C;
     205             :   (void)src_width;
     206             :   (void)src_height;
     207           0 :   assert(IS_ALIGNED(src_width, 2));
     208           0 :   assert(IS_ALIGNED(src_height, 2));
     209           0 :   src_argb += (y >> 16) * src_stride + (x >> 16) * 4;
     210             : #if defined(HAS_SCALEARGBROWDOWNEVEN_SSE2)
     211           0 :   if (TestCpuFlag(kCpuHasSSE2)) {
     212           0 :     ScaleARGBRowDownEven = filtering ? ScaleARGBRowDownEvenBox_Any_SSE2
     213             :                                      : ScaleARGBRowDownEven_Any_SSE2;
     214           0 :     if (IS_ALIGNED(dst_width, 4)) {
     215           0 :       ScaleARGBRowDownEven =
     216           0 :           filtering ? ScaleARGBRowDownEvenBox_SSE2 : ScaleARGBRowDownEven_SSE2;
     217             :     }
     218             :   }
     219             : #endif
     220             : #if defined(HAS_SCALEARGBROWDOWNEVEN_NEON)
     221             :   if (TestCpuFlag(kCpuHasNEON)) {
     222             :     ScaleARGBRowDownEven = filtering ? ScaleARGBRowDownEvenBox_Any_NEON
     223             :                                      : ScaleARGBRowDownEven_Any_NEON;
     224             :     if (IS_ALIGNED(dst_width, 4)) {
     225             :       ScaleARGBRowDownEven =
     226             :           filtering ? ScaleARGBRowDownEvenBox_NEON : ScaleARGBRowDownEven_NEON;
     227             :     }
     228             :   }
     229             : #endif
     230             : #if defined(HAS_SCALEARGBROWDOWNEVEN_MSA)
     231             :   if (TestCpuFlag(kCpuHasMSA)) {
     232             :     ScaleARGBRowDownEven = filtering ? ScaleARGBRowDownEvenBox_Any_MSA
     233             :                                      : ScaleARGBRowDownEven_Any_MSA;
     234             :     if (IS_ALIGNED(dst_width, 4)) {
     235             :       ScaleARGBRowDownEven =
     236             :           filtering ? ScaleARGBRowDownEvenBox_MSA : ScaleARGBRowDownEven_MSA;
     237             :     }
     238             :   }
     239             : #endif
     240             : 
     241           0 :   if (filtering == kFilterLinear) {
     242           0 :     src_stride = 0;
     243             :   }
     244           0 :   for (j = 0; j < dst_height; ++j) {
     245           0 :     ScaleARGBRowDownEven(src_argb, src_stride, col_step, dst_argb, dst_width);
     246           0 :     src_argb += row_stride;
     247           0 :     dst_argb += dst_stride;
     248             :   }
     249           0 : }
     250             : 
     251             : // Scale ARGB down with bilinear interpolation.
     252           0 : static void ScaleARGBBilinearDown(int src_width,
     253             :                                   int src_height,
     254             :                                   int dst_width,
     255             :                                   int dst_height,
     256             :                                   int src_stride,
     257             :                                   int dst_stride,
     258             :                                   const uint8* src_argb,
     259             :                                   uint8* dst_argb,
     260             :                                   int x,
     261             :                                   int dx,
     262             :                                   int y,
     263             :                                   int dy,
     264             :                                   enum FilterMode filtering) {
     265             :   int j;
     266             :   void (*InterpolateRow)(uint8 * dst_argb, const uint8* src_argb,
     267             :                          ptrdiff_t src_stride, int dst_width,
     268           0 :                          int source_y_fraction) = InterpolateRow_C;
     269             :   void (*ScaleARGBFilterCols)(uint8 * dst_argb, const uint8* src_argb,
     270             :                               int dst_width, int x, int dx) =
     271           0 :       (src_width >= 32768) ? ScaleARGBFilterCols64_C : ScaleARGBFilterCols_C;
     272           0 :   int64 xlast = x + (int64)(dst_width - 1) * dx;
     273           0 :   int64 xl = (dx >= 0) ? x : xlast;
     274           0 :   int64 xr = (dx >= 0) ? xlast : x;
     275             :   int clip_src_width;
     276           0 :   xl = (xl >> 16) & ~3;    // Left edge aligned.
     277           0 :   xr = (xr >> 16) + 1;     // Right most pixel used.  Bilinear uses 2 pixels.
     278           0 :   xr = (xr + 1 + 3) & ~3;  // 1 beyond 4 pixel aligned right most pixel.
     279           0 :   if (xr > src_width) {
     280           0 :     xr = src_width;
     281             :   }
     282           0 :   clip_src_width = (int)(xr - xl) * 4;  // Width aligned to 4.
     283           0 :   src_argb += xl * 4;
     284           0 :   x -= (int)(xl << 16);
     285             : #if defined(HAS_INTERPOLATEROW_SSSE3)
     286           0 :   if (TestCpuFlag(kCpuHasSSSE3)) {
     287           0 :     InterpolateRow = InterpolateRow_Any_SSSE3;
     288           0 :     if (IS_ALIGNED(clip_src_width, 16)) {
     289           0 :       InterpolateRow = InterpolateRow_SSSE3;
     290             :     }
     291             :   }
     292             : #endif
     293             : #if defined(HAS_INTERPOLATEROW_AVX2)
     294           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
     295           0 :     InterpolateRow = InterpolateRow_Any_AVX2;
     296           0 :     if (IS_ALIGNED(clip_src_width, 32)) {
     297           0 :       InterpolateRow = InterpolateRow_AVX2;
     298             :     }
     299             :   }
     300             : #endif
     301             : #if defined(HAS_INTERPOLATEROW_NEON)
     302             :   if (TestCpuFlag(kCpuHasNEON)) {
     303             :     InterpolateRow = InterpolateRow_Any_NEON;
     304             :     if (IS_ALIGNED(clip_src_width, 16)) {
     305             :       InterpolateRow = InterpolateRow_NEON;
     306             :     }
     307             :   }
     308             : #endif
     309             : #if defined(HAS_INTERPOLATEROW_DSPR2)
     310             :   if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(src_argb, 4) &&
     311             :       IS_ALIGNED(src_stride, 4)) {
     312             :     InterpolateRow = InterpolateRow_Any_DSPR2;
     313             :     if (IS_ALIGNED(clip_src_width, 4)) {
     314             :       InterpolateRow = InterpolateRow_DSPR2;
     315             :     }
     316             :   }
     317             : #endif
     318             : #if defined(HAS_SCALEARGBFILTERCOLS_SSSE3)
     319           0 :   if (TestCpuFlag(kCpuHasSSSE3) && src_width < 32768) {
     320           0 :     ScaleARGBFilterCols = ScaleARGBFilterCols_SSSE3;
     321             :   }
     322             : #endif
     323             : #if defined(HAS_SCALEARGBFILTERCOLS_NEON)
     324             :   if (TestCpuFlag(kCpuHasNEON)) {
     325             :     ScaleARGBFilterCols = ScaleARGBFilterCols_Any_NEON;
     326             :     if (IS_ALIGNED(dst_width, 4)) {
     327             :       ScaleARGBFilterCols = ScaleARGBFilterCols_NEON;
     328             :     }
     329             :   }
     330             : #endif
     331             :   // TODO(fbarchard): Consider not allocating row buffer for kFilterLinear.
     332             :   // Allocate a row of ARGB.
     333             :   {
     334           0 :     align_buffer_64(row, clip_src_width * 4);
     335             : 
     336           0 :     const int max_y = (src_height - 1) << 16;
     337           0 :     if (y > max_y) {
     338           0 :       y = max_y;
     339             :     }
     340           0 :     for (j = 0; j < dst_height; ++j) {
     341           0 :       int yi = y >> 16;
     342           0 :       const uint8* src = src_argb + yi * src_stride;
     343           0 :       if (filtering == kFilterLinear) {
     344           0 :         ScaleARGBFilterCols(dst_argb, src, dst_width, x, dx);
     345             :       } else {
     346           0 :         int yf = (y >> 8) & 255;
     347           0 :         InterpolateRow(row, src, src_stride, clip_src_width, yf);
     348           0 :         ScaleARGBFilterCols(dst_argb, row, dst_width, x, dx);
     349             :       }
     350           0 :       dst_argb += dst_stride;
     351           0 :       y += dy;
     352           0 :       if (y > max_y) {
     353           0 :         y = max_y;
     354             :       }
     355             :     }
     356           0 :     free_aligned_buffer_64(row);
     357             :   }
     358           0 : }
     359             : 
     360             : // Scale ARGB up with bilinear interpolation.
     361           0 : static void ScaleARGBBilinearUp(int src_width,
     362             :                                 int src_height,
     363             :                                 int dst_width,
     364             :                                 int dst_height,
     365             :                                 int src_stride,
     366             :                                 int dst_stride,
     367             :                                 const uint8* src_argb,
     368             :                                 uint8* dst_argb,
     369             :                                 int x,
     370             :                                 int dx,
     371             :                                 int y,
     372             :                                 int dy,
     373             :                                 enum FilterMode filtering) {
     374             :   int j;
     375             :   void (*InterpolateRow)(uint8 * dst_argb, const uint8* src_argb,
     376             :                          ptrdiff_t src_stride, int dst_width,
     377           0 :                          int source_y_fraction) = InterpolateRow_C;
     378             :   void (*ScaleARGBFilterCols)(uint8 * dst_argb, const uint8* src_argb,
     379             :                               int dst_width, int x, int dx) =
     380           0 :       filtering ? ScaleARGBFilterCols_C : ScaleARGBCols_C;
     381           0 :   const int max_y = (src_height - 1) << 16;
     382             : #if defined(HAS_INTERPOLATEROW_SSSE3)
     383           0 :   if (TestCpuFlag(kCpuHasSSSE3)) {
     384           0 :     InterpolateRow = InterpolateRow_Any_SSSE3;
     385           0 :     if (IS_ALIGNED(dst_width, 4)) {
     386           0 :       InterpolateRow = InterpolateRow_SSSE3;
     387             :     }
     388             :   }
     389             : #endif
     390             : #if defined(HAS_INTERPOLATEROW_AVX2)
     391           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
     392           0 :     InterpolateRow = InterpolateRow_Any_AVX2;
     393           0 :     if (IS_ALIGNED(dst_width, 8)) {
     394           0 :       InterpolateRow = InterpolateRow_AVX2;
     395             :     }
     396             :   }
     397             : #endif
     398             : #if defined(HAS_INTERPOLATEROW_NEON)
     399             :   if (TestCpuFlag(kCpuHasNEON)) {
     400             :     InterpolateRow = InterpolateRow_Any_NEON;
     401             :     if (IS_ALIGNED(dst_width, 4)) {
     402             :       InterpolateRow = InterpolateRow_NEON;
     403             :     }
     404             :   }
     405             : #endif
     406             : #if defined(HAS_INTERPOLATEROW_DSPR2)
     407             :   if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(dst_argb, 4) &&
     408             :       IS_ALIGNED(dst_stride, 4)) {
     409             :     InterpolateRow = InterpolateRow_DSPR2;
     410             :   }
     411             : #endif
     412           0 :   if (src_width >= 32768) {
     413           0 :     ScaleARGBFilterCols =
     414           0 :         filtering ? ScaleARGBFilterCols64_C : ScaleARGBCols64_C;
     415             :   }
     416             : #if defined(HAS_SCALEARGBFILTERCOLS_SSSE3)
     417           0 :   if (filtering && TestCpuFlag(kCpuHasSSSE3) && src_width < 32768) {
     418           0 :     ScaleARGBFilterCols = ScaleARGBFilterCols_SSSE3;
     419             :   }
     420             : #endif
     421             : #if defined(HAS_SCALEARGBFILTERCOLS_NEON)
     422             :   if (filtering && TestCpuFlag(kCpuHasNEON)) {
     423             :     ScaleARGBFilterCols = ScaleARGBFilterCols_Any_NEON;
     424             :     if (IS_ALIGNED(dst_width, 4)) {
     425             :       ScaleARGBFilterCols = ScaleARGBFilterCols_NEON;
     426             :     }
     427             :   }
     428             : #endif
     429             : #if defined(HAS_SCALEARGBCOLS_SSE2)
     430           0 :   if (!filtering && TestCpuFlag(kCpuHasSSE2) && src_width < 32768) {
     431           0 :     ScaleARGBFilterCols = ScaleARGBCols_SSE2;
     432             :   }
     433             : #endif
     434             : #if defined(HAS_SCALEARGBCOLS_NEON)
     435             :   if (!filtering && TestCpuFlag(kCpuHasNEON)) {
     436             :     ScaleARGBFilterCols = ScaleARGBCols_Any_NEON;
     437             :     if (IS_ALIGNED(dst_width, 8)) {
     438             :       ScaleARGBFilterCols = ScaleARGBCols_NEON;
     439             :     }
     440             :   }
     441             : #endif
     442           0 :   if (!filtering && src_width * 2 == dst_width && x < 0x8000) {
     443           0 :     ScaleARGBFilterCols = ScaleARGBColsUp2_C;
     444             : #if defined(HAS_SCALEARGBCOLSUP2_SSE2)
     445           0 :     if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(dst_width, 8)) {
     446           0 :       ScaleARGBFilterCols = ScaleARGBColsUp2_SSE2;
     447             :     }
     448             : #endif
     449             :   }
     450             : 
     451           0 :   if (y > max_y) {
     452           0 :     y = max_y;
     453             :   }
     454             : 
     455             :   {
     456           0 :     int yi = y >> 16;
     457           0 :     const uint8* src = src_argb + yi * src_stride;
     458             : 
     459             :     // Allocate 2 rows of ARGB.
     460           0 :     const int kRowSize = (dst_width * 4 + 31) & ~31;
     461           0 :     align_buffer_64(row, kRowSize * 2);
     462             : 
     463           0 :     uint8* rowptr = row;
     464           0 :     int rowstride = kRowSize;
     465           0 :     int lasty = yi;
     466             : 
     467           0 :     ScaleARGBFilterCols(rowptr, src, dst_width, x, dx);
     468           0 :     if (src_height > 1) {
     469           0 :       src += src_stride;
     470             :     }
     471           0 :     ScaleARGBFilterCols(rowptr + rowstride, src, dst_width, x, dx);
     472           0 :     src += src_stride;
     473             : 
     474           0 :     for (j = 0; j < dst_height; ++j) {
     475           0 :       yi = y >> 16;
     476           0 :       if (yi != lasty) {
     477           0 :         if (y > max_y) {
     478           0 :           y = max_y;
     479           0 :           yi = y >> 16;
     480           0 :           src = src_argb + yi * src_stride;
     481             :         }
     482           0 :         if (yi != lasty) {
     483           0 :           ScaleARGBFilterCols(rowptr, src, dst_width, x, dx);
     484           0 :           rowptr += rowstride;
     485           0 :           rowstride = -rowstride;
     486           0 :           lasty = yi;
     487           0 :           src += src_stride;
     488             :         }
     489             :       }
     490           0 :       if (filtering == kFilterLinear) {
     491           0 :         InterpolateRow(dst_argb, rowptr, 0, dst_width * 4, 0);
     492             :       } else {
     493           0 :         int yf = (y >> 8) & 255;
     494           0 :         InterpolateRow(dst_argb, rowptr, rowstride, dst_width * 4, yf);
     495             :       }
     496           0 :       dst_argb += dst_stride;
     497           0 :       y += dy;
     498             :     }
     499           0 :     free_aligned_buffer_64(row);
     500             :   }
     501           0 : }
     502             : 
     503             : #ifdef YUVSCALEUP
     504             : // Scale YUV to ARGB up with bilinear interpolation.
     505             : static void ScaleYUVToARGBBilinearUp(int src_width,
     506             :                                      int src_height,
     507             :                                      int dst_width,
     508             :                                      int dst_height,
     509             :                                      int src_stride_y,
     510             :                                      int src_stride_u,
     511             :                                      int src_stride_v,
     512             :                                      int dst_stride_argb,
     513             :                                      const uint8* src_y,
     514             :                                      const uint8* src_u,
     515             :                                      const uint8* src_v,
     516             :                                      uint8* dst_argb,
     517             :                                      int x,
     518             :                                      int dx,
     519             :                                      int y,
     520             :                                      int dy,
     521             :                                      enum FilterMode filtering) {
     522             :   int j;
     523             :   void (*I422ToARGBRow)(const uint8* y_buf, const uint8* u_buf,
     524             :                         const uint8* v_buf, uint8* rgb_buf, int width) =
     525             :       I422ToARGBRow_C;
     526             : #if defined(HAS_I422TOARGBROW_SSSE3)
     527             :   if (TestCpuFlag(kCpuHasSSSE3)) {
     528             :     I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
     529             :     if (IS_ALIGNED(src_width, 8)) {
     530             :       I422ToARGBRow = I422ToARGBRow_SSSE3;
     531             :     }
     532             :   }
     533             : #endif
     534             : #if defined(HAS_I422TOARGBROW_AVX2)
     535             :   if (TestCpuFlag(kCpuHasAVX2)) {
     536             :     I422ToARGBRow = I422ToARGBRow_Any_AVX2;
     537             :     if (IS_ALIGNED(src_width, 16)) {
     538             :       I422ToARGBRow = I422ToARGBRow_AVX2;
     539             :     }
     540             :   }
     541             : #endif
     542             : #if defined(HAS_I422TOARGBROW_NEON)
     543             :   if (TestCpuFlag(kCpuHasNEON)) {
     544             :     I422ToARGBRow = I422ToARGBRow_Any_NEON;
     545             :     if (IS_ALIGNED(src_width, 8)) {
     546             :       I422ToARGBRow = I422ToARGBRow_NEON;
     547             :     }
     548             :   }
     549             : #endif
     550             : #if defined(HAS_I422TOARGBROW_DSPR2)
     551             :   if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(src_width, 4) &&
     552             :       IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
     553             :       IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
     554             :       IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) &&
     555             :       IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride_argb, 4)) {
     556             :     I422ToARGBRow = I422ToARGBRow_DSPR2;
     557             :   }
     558             : #endif
     559             : #if defined(HAS_I422TOARGBROW_MSA)
     560             :   if (TestCpuFlag(kCpuHasMSA)) {
     561             :     I422ToARGBRow = I422ToARGBRow_Any_MSA;
     562             :     if (IS_ALIGNED(src_width, 8)) {
     563             :       I422ToARGBRow = I422ToARGBRow_MSA;
     564             :     }
     565             :   }
     566             : #endif
     567             : 
     568             :   void (*InterpolateRow)(uint8 * dst_argb, const uint8* src_argb,
     569             :                          ptrdiff_t src_stride, int dst_width,
     570             :                          int source_y_fraction) = InterpolateRow_C;
     571             : #if defined(HAS_INTERPOLATEROW_SSSE3)
     572             :   if (TestCpuFlag(kCpuHasSSSE3)) {
     573             :     InterpolateRow = InterpolateRow_Any_SSSE3;
     574             :     if (IS_ALIGNED(dst_width, 4)) {
     575             :       InterpolateRow = InterpolateRow_SSSE3;
     576             :     }
     577             :   }
     578             : #endif
     579             : #if defined(HAS_INTERPOLATEROW_AVX2)
     580             :   if (TestCpuFlag(kCpuHasAVX2)) {
     581             :     InterpolateRow = InterpolateRow_Any_AVX2;
     582             :     if (IS_ALIGNED(dst_width, 8)) {
     583             :       InterpolateRow = InterpolateRow_AVX2;
     584             :     }
     585             :   }
     586             : #endif
     587             : #if defined(HAS_INTERPOLATEROW_NEON)
     588             :   if (TestCpuFlag(kCpuHasNEON)) {
     589             :     InterpolateRow = InterpolateRow_Any_NEON;
     590             :     if (IS_ALIGNED(dst_width, 4)) {
     591             :       InterpolateRow = InterpolateRow_NEON;
     592             :     }
     593             :   }
     594             : #endif
     595             : #if defined(HAS_INTERPOLATEROW_DSPR2)
     596             :   if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(dst_argb, 4) &&
     597             :       IS_ALIGNED(dst_stride_argb, 4)) {
     598             :     InterpolateRow = InterpolateRow_DSPR2;
     599             :   }
     600             : #endif
     601             : 
     602             :   void (*ScaleARGBFilterCols)(uint8 * dst_argb, const uint8* src_argb,
     603             :                               int dst_width, int x, int dx) =
     604             :       filtering ? ScaleARGBFilterCols_C : ScaleARGBCols_C;
     605             :   if (src_width >= 32768) {
     606             :     ScaleARGBFilterCols =
     607             :         filtering ? ScaleARGBFilterCols64_C : ScaleARGBCols64_C;
     608             :   }
     609             : #if defined(HAS_SCALEARGBFILTERCOLS_SSSE3)
     610             :   if (filtering && TestCpuFlag(kCpuHasSSSE3) && src_width < 32768) {
     611             :     ScaleARGBFilterCols = ScaleARGBFilterCols_SSSE3;
     612             :   }
     613             : #endif
     614             : #if defined(HAS_SCALEARGBFILTERCOLS_NEON)
     615             :   if (filtering && TestCpuFlag(kCpuHasNEON)) {
     616             :     ScaleARGBFilterCols = ScaleARGBFilterCols_Any_NEON;
     617             :     if (IS_ALIGNED(dst_width, 4)) {
     618             :       ScaleARGBFilterCols = ScaleARGBFilterCols_NEON;
     619             :     }
     620             :   }
     621             : #endif
     622             : #if defined(HAS_SCALEARGBCOLS_SSE2)
     623             :   if (!filtering && TestCpuFlag(kCpuHasSSE2) && src_width < 32768) {
     624             :     ScaleARGBFilterCols = ScaleARGBCols_SSE2;
     625             :   }
     626             : #endif
     627             : #if defined(HAS_SCALEARGBCOLS_NEON)
     628             :   if (!filtering && TestCpuFlag(kCpuHasNEON)) {
     629             :     ScaleARGBFilterCols = ScaleARGBCols_Any_NEON;
     630             :     if (IS_ALIGNED(dst_width, 8)) {
     631             :       ScaleARGBFilterCols = ScaleARGBCols_NEON;
     632             :     }
     633             :   }
     634             : #endif
     635             :   if (!filtering && src_width * 2 == dst_width && x < 0x8000) {
     636             :     ScaleARGBFilterCols = ScaleARGBColsUp2_C;
     637             : #if defined(HAS_SCALEARGBCOLSUP2_SSE2)
     638             :     if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(dst_width, 8)) {
     639             :       ScaleARGBFilterCols = ScaleARGBColsUp2_SSE2;
     640             :     }
     641             : #endif
     642             :   }
     643             : 
     644             :   const int max_y = (src_height - 1) << 16;
     645             :   if (y > max_y) {
     646             :     y = max_y;
     647             :   }
     648             :   const int kYShift = 1;  // Shift Y by 1 to convert Y plane to UV coordinate.
     649             :   int yi = y >> 16;
     650             :   int uv_yi = yi >> kYShift;
     651             :   const uint8* src_row_y = src_y + yi * src_stride_y;
     652             :   const uint8* src_row_u = src_u + uv_yi * src_stride_u;
     653             :   const uint8* src_row_v = src_v + uv_yi * src_stride_v;
     654             : 
     655             :   // Allocate 2 rows of ARGB.
     656             :   const int kRowSize = (dst_width * 4 + 31) & ~31;
     657             :   align_buffer_64(row, kRowSize * 2);
     658             : 
     659             :   // Allocate 1 row of ARGB for source conversion.
     660             :   align_buffer_64(argb_row, src_width * 4);
     661             : 
     662             :   uint8* rowptr = row;
     663             :   int rowstride = kRowSize;
     664             :   int lasty = yi;
     665             : 
     666             :   // TODO(fbarchard): Convert first 2 rows of YUV to ARGB.
     667             :   ScaleARGBFilterCols(rowptr, src_row_y, dst_width, x, dx);
     668             :   if (src_height > 1) {
     669             :     src_row_y += src_stride_y;
     670             :     if (yi & 1) {
     671             :       src_row_u += src_stride_u;
     672             :       src_row_v += src_stride_v;
     673             :     }
     674             :   }
     675             :   ScaleARGBFilterCols(rowptr + rowstride, src_row_y, dst_width, x, dx);
     676             :   if (src_height > 2) {
     677             :     src_row_y += src_stride_y;
     678             :     if (!(yi & 1)) {
     679             :       src_row_u += src_stride_u;
     680             :       src_row_v += src_stride_v;
     681             :     }
     682             :   }
     683             : 
     684             :   for (j = 0; j < dst_height; ++j) {
     685             :     yi = y >> 16;
     686             :     if (yi != lasty) {
     687             :       if (y > max_y) {
     688             :         y = max_y;
     689             :         yi = y >> 16;
     690             :         uv_yi = yi >> kYShift;
     691             :         src_row_y = src_y + yi * src_stride_y;
     692             :         src_row_u = src_u + uv_yi * src_stride_u;
     693             :         src_row_v = src_v + uv_yi * src_stride_v;
     694             :       }
     695             :       if (yi != lasty) {
     696             :         // TODO(fbarchard): Convert the clipped region of row.
     697             :         I422ToARGBRow(src_row_y, src_row_u, src_row_v, argb_row, src_width);
     698             :         ScaleARGBFilterCols(rowptr, argb_row, dst_width, x, dx);
     699             :         rowptr += rowstride;
     700             :         rowstride = -rowstride;
     701             :         lasty = yi;
     702             :         src_row_y += src_stride_y;
     703             :         if (yi & 1) {
     704             :           src_row_u += src_stride_u;
     705             :           src_row_v += src_stride_v;
     706             :         }
     707             :       }
     708             :     }
     709             :     if (filtering == kFilterLinear) {
     710             :       InterpolateRow(dst_argb, rowptr, 0, dst_width * 4, 0);
     711             :     } else {
     712             :       int yf = (y >> 8) & 255;
     713             :       InterpolateRow(dst_argb, rowptr, rowstride, dst_width * 4, yf);
     714             :     }
     715             :     dst_argb += dst_stride_argb;
     716             :     y += dy;
     717             :   }
     718             :   free_aligned_buffer_64(row);
     719             :   free_aligned_buffer_64(row_argb);
     720             : }
     721             : #endif
     722             : 
     723             : // Scale ARGB to/from any dimensions, without interpolation.
     724             : // Fixed point math is used for performance: The upper 16 bits
     725             : // of x and dx is the integer part of the source position and
     726             : // the lower 16 bits are the fixed decimal part.
     727             : 
     728           0 : static void ScaleARGBSimple(int src_width,
     729             :                             int src_height,
     730             :                             int dst_width,
     731             :                             int dst_height,
     732             :                             int src_stride,
     733             :                             int dst_stride,
     734             :                             const uint8* src_argb,
     735             :                             uint8* dst_argb,
     736             :                             int x,
     737             :                             int dx,
     738             :                             int y,
     739             :                             int dy) {
     740             :   int j;
     741             :   void (*ScaleARGBCols)(uint8 * dst_argb, const uint8* src_argb, int dst_width,
     742             :                         int x, int dx) =
     743           0 :       (src_width >= 32768) ? ScaleARGBCols64_C : ScaleARGBCols_C;
     744             :   (void)src_height;
     745             : #if defined(HAS_SCALEARGBCOLS_SSE2)
     746           0 :   if (TestCpuFlag(kCpuHasSSE2) && src_width < 32768) {
     747           0 :     ScaleARGBCols = ScaleARGBCols_SSE2;
     748             :   }
     749             : #endif
     750             : #if defined(HAS_SCALEARGBCOLS_NEON)
     751             :   if (TestCpuFlag(kCpuHasNEON)) {
     752             :     ScaleARGBCols = ScaleARGBCols_Any_NEON;
     753             :     if (IS_ALIGNED(dst_width, 8)) {
     754             :       ScaleARGBCols = ScaleARGBCols_NEON;
     755             :     }
     756             :   }
     757             : #endif
     758           0 :   if (src_width * 2 == dst_width && x < 0x8000) {
     759           0 :     ScaleARGBCols = ScaleARGBColsUp2_C;
     760             : #if defined(HAS_SCALEARGBCOLSUP2_SSE2)
     761           0 :     if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(dst_width, 8)) {
     762           0 :       ScaleARGBCols = ScaleARGBColsUp2_SSE2;
     763             :     }
     764             : #endif
     765             :   }
     766             : 
     767           0 :   for (j = 0; j < dst_height; ++j) {
     768           0 :     ScaleARGBCols(dst_argb, src_argb + (y >> 16) * src_stride, dst_width, x,
     769           0 :                   dx);
     770           0 :     dst_argb += dst_stride;
     771           0 :     y += dy;
     772             :   }
     773           0 : }
     774             : 
     775             : // ScaleARGB a ARGB.
     776             : // This function in turn calls a scaling function
     777             : // suitable for handling the desired resolutions.
     778           0 : static void ScaleARGB(const uint8* src,
     779             :                       int src_stride,
     780             :                       int src_width,
     781             :                       int src_height,
     782             :                       uint8* dst,
     783             :                       int dst_stride,
     784             :                       int dst_width,
     785             :                       int dst_height,
     786             :                       int clip_x,
     787             :                       int clip_y,
     788             :                       int clip_width,
     789             :                       int clip_height,
     790             :                       enum FilterMode filtering) {
     791             :   // Initial source x/y coordinate and step values as 16.16 fixed point.
     792           0 :   int x = 0;
     793           0 :   int y = 0;
     794           0 :   int dx = 0;
     795           0 :   int dy = 0;
     796             :   // ARGB does not support box filter yet, but allow the user to pass it.
     797             :   // Simplify filtering when possible.
     798             :   filtering = ScaleFilterReduce(src_width, src_height, dst_width, dst_height,
     799           0 :                                 filtering);
     800             : 
     801             :   // Negative src_height means invert the image.
     802           0 :   if (src_height < 0) {
     803           0 :     src_height = -src_height;
     804           0 :     src = src + (src_height - 1) * src_stride;
     805           0 :     src_stride = -src_stride;
     806             :   }
     807             :   ScaleSlope(src_width, src_height, dst_width, dst_height, filtering, &x, &y,
     808           0 :              &dx, &dy);
     809           0 :   src_width = Abs(src_width);
     810           0 :   if (clip_x) {
     811           0 :     int64 clipf = (int64)(clip_x)*dx;
     812           0 :     x += (clipf & 0xffff);
     813           0 :     src += (clipf >> 16) * 4;
     814           0 :     dst += clip_x * 4;
     815             :   }
     816           0 :   if (clip_y) {
     817           0 :     int64 clipf = (int64)(clip_y)*dy;
     818           0 :     y += (clipf & 0xffff);
     819           0 :     src += (clipf >> 16) * src_stride;
     820           0 :     dst += clip_y * dst_stride;
     821             :   }
     822             : 
     823             :   // Special case for integer step values.
     824           0 :   if (((dx | dy) & 0xffff) == 0) {
     825           0 :     if (!dx || !dy) {  // 1 pixel wide and/or tall.
     826           0 :       filtering = kFilterNone;
     827             :     } else {
     828             :       // Optimized even scale down. ie 2, 4, 6, 8, 10x.
     829           0 :       if (!(dx & 0x10000) && !(dy & 0x10000)) {
     830           0 :         if (dx == 0x20000) {
     831             :           // Optimized 1/2 downsample.
     832             :           ScaleARGBDown2(src_width, src_height, clip_width, clip_height,
     833             :                          src_stride, dst_stride, src, dst, x, dx, y, dy,
     834           0 :                          filtering);
     835           0 :           return;
     836             :         }
     837           0 :         if (dx == 0x40000 && filtering == kFilterBox) {
     838             :           // Optimized 1/4 box downsample.
     839             :           ScaleARGBDown4Box(src_width, src_height, clip_width, clip_height,
     840           0 :                             src_stride, dst_stride, src, dst, x, dx, y, dy);
     841           0 :           return;
     842             :         }
     843             :         ScaleARGBDownEven(src_width, src_height, clip_width, clip_height,
     844             :                           src_stride, dst_stride, src, dst, x, dx, y, dy,
     845           0 :                           filtering);
     846           0 :         return;
     847             :       }
     848             :       // Optimized odd scale down. ie 3, 5, 7, 9x.
     849           0 :       if ((dx & 0x10000) && (dy & 0x10000)) {
     850           0 :         filtering = kFilterNone;
     851           0 :         if (dx == 0x10000 && dy == 0x10000) {
     852             :           // Straight copy.
     853           0 :           ARGBCopy(src + (y >> 16) * src_stride + (x >> 16) * 4, src_stride,
     854           0 :                    dst, dst_stride, clip_width, clip_height);
     855           0 :           return;
     856             :         }
     857             :       }
     858             :     }
     859             :   }
     860           0 :   if (dx == 0x10000 && (x & 0xffff) == 0) {
     861             :     // Arbitrary scale vertically, but unscaled vertically.
     862             :     ScalePlaneVertical(src_height, clip_width, clip_height, src_stride,
     863           0 :                        dst_stride, src, dst, x, y, dy, 4, filtering);
     864           0 :     return;
     865             :   }
     866           0 :   if (filtering && dy < 65536) {
     867             :     ScaleARGBBilinearUp(src_width, src_height, clip_width, clip_height,
     868             :                         src_stride, dst_stride, src, dst, x, dx, y, dy,
     869           0 :                         filtering);
     870           0 :     return;
     871             :   }
     872           0 :   if (filtering) {
     873             :     ScaleARGBBilinearDown(src_width, src_height, clip_width, clip_height,
     874             :                           src_stride, dst_stride, src, dst, x, dx, y, dy,
     875           0 :                           filtering);
     876           0 :     return;
     877             :   }
     878             :   ScaleARGBSimple(src_width, src_height, clip_width, clip_height, src_stride,
     879           0 :                   dst_stride, src, dst, x, dx, y, dy);
     880             : }
     881             : 
     882             : LIBYUV_API
     883           0 : int ARGBScaleClip(const uint8* src_argb,
     884             :                   int src_stride_argb,
     885             :                   int src_width,
     886             :                   int src_height,
     887             :                   uint8* dst_argb,
     888             :                   int dst_stride_argb,
     889             :                   int dst_width,
     890             :                   int dst_height,
     891             :                   int clip_x,
     892             :                   int clip_y,
     893             :                   int clip_width,
     894             :                   int clip_height,
     895             :                   enum FilterMode filtering) {
     896           0 :   if (!src_argb || src_width == 0 || src_height == 0 || !dst_argb ||
     897           0 :       dst_width <= 0 || dst_height <= 0 || clip_x < 0 || clip_y < 0 ||
     898           0 :       clip_width > 32768 || clip_height > 32768 ||
     899           0 :       (clip_x + clip_width) > dst_width ||
     900           0 :       (clip_y + clip_height) > dst_height) {
     901           0 :     return -1;
     902             :   }
     903             :   ScaleARGB(src_argb, src_stride_argb, src_width, src_height, dst_argb,
     904             :             dst_stride_argb, dst_width, dst_height, clip_x, clip_y, clip_width,
     905           0 :             clip_height, filtering);
     906           0 :   return 0;
     907             : }
     908             : 
     909             : // Scale an ARGB image.
     910             : LIBYUV_API
     911           0 : int ARGBScale(const uint8* src_argb,
     912             :               int src_stride_argb,
     913             :               int src_width,
     914             :               int src_height,
     915             :               uint8* dst_argb,
     916             :               int dst_stride_argb,
     917             :               int dst_width,
     918             :               int dst_height,
     919             :               enum FilterMode filtering) {
     920           0 :   if (!src_argb || src_width == 0 || src_height == 0 || src_width > 32768 ||
     921           0 :       src_height > 32768 || !dst_argb || dst_width <= 0 || dst_height <= 0) {
     922           0 :     return -1;
     923             :   }
     924             :   ScaleARGB(src_argb, src_stride_argb, src_width, src_height, dst_argb,
     925             :             dst_stride_argb, dst_width, dst_height, 0, 0, dst_width, dst_height,
     926           0 :             filtering);
     927           0 :   return 0;
     928             : }
     929             : 
     930             : // Scale with YUV conversion to ARGB and clipping.
     931             : LIBYUV_API
     932           0 : int YUVToARGBScaleClip(const uint8* src_y,
     933             :                        int src_stride_y,
     934             :                        const uint8* src_u,
     935             :                        int src_stride_u,
     936             :                        const uint8* src_v,
     937             :                        int src_stride_v,
     938             :                        uint32 src_fourcc,
     939             :                        int src_width,
     940             :                        int src_height,
     941             :                        uint8* dst_argb,
     942             :                        int dst_stride_argb,
     943             :                        uint32 dst_fourcc,
     944             :                        int dst_width,
     945             :                        int dst_height,
     946             :                        int clip_x,
     947             :                        int clip_y,
     948             :                        int clip_width,
     949             :                        int clip_height,
     950             :                        enum FilterMode filtering) {
     951           0 :   uint8* argb_buffer = (uint8*)malloc(src_width * src_height * 4);
     952             :   int r;
     953             :   (void)src_fourcc;  // TODO(fbarchard): implement and/or assert.
     954             :   (void)dst_fourcc;
     955           0 :   I420ToARGB(src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v,
     956           0 :              argb_buffer, src_width * 4, src_width, src_height);
     957             : 
     958           0 :   r = ARGBScaleClip(argb_buffer, src_width * 4, src_width, src_height, dst_argb,
     959             :                     dst_stride_argb, dst_width, dst_height, clip_x, clip_y,
     960           0 :                     clip_width, clip_height, filtering);
     961           0 :   free(argb_buffer);
     962           0 :   return r;
     963             : }
     964             : 
     965             : #ifdef __cplusplus
     966             : }  // extern "C"
     967             : }  // namespace libyuv
     968             : #endif

Generated by: LCOV version 1.13