LCOV - code coverage report
Current view: top level - media/libyuv/libyuv/source - scale.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 652 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 30 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 CopyPlane
      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             : #define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)
      31             : 
      32             : // Scale plane, 1/2
      33             : // This is an optimized version for scaling down a plane to 1/2 of
      34             : // its original size.
      35             : 
      36           0 : static void ScalePlaneDown2(int src_width,
      37             :                             int src_height,
      38             :                             int dst_width,
      39             :                             int dst_height,
      40             :                             int src_stride,
      41             :                             int dst_stride,
      42             :                             const uint8* src_ptr,
      43             :                             uint8* dst_ptr,
      44             :                             enum FilterMode filtering) {
      45             :   int y;
      46             :   void (*ScaleRowDown2)(const uint8* src_ptr, ptrdiff_t src_stride,
      47             :                         uint8* dst_ptr, int dst_width) =
      48             :       filtering == kFilterNone
      49           0 :           ? ScaleRowDown2_C
      50           0 :           : (filtering == kFilterLinear ? ScaleRowDown2Linear_C
      51           0 :                                         : ScaleRowDown2Box_C);
      52           0 :   int row_stride = src_stride << 1;
      53             :   (void)src_width;
      54             :   (void)src_height;
      55           0 :   if (!filtering) {
      56           0 :     src_ptr += src_stride;  // Point to odd rows.
      57           0 :     src_stride = 0;
      58             :   }
      59             : 
      60             : #if defined(HAS_SCALEROWDOWN2_NEON)
      61             :   if (TestCpuFlag(kCpuHasNEON)) {
      62             :     ScaleRowDown2 =
      63             :         filtering == kFilterNone
      64             :             ? ScaleRowDown2_Any_NEON
      65             :             : (filtering == kFilterLinear ? ScaleRowDown2Linear_Any_NEON
      66             :                                           : ScaleRowDown2Box_Any_NEON);
      67             :     if (IS_ALIGNED(dst_width, 16)) {
      68             :       ScaleRowDown2 = filtering == kFilterNone ? ScaleRowDown2_NEON
      69             :                                                : (filtering == kFilterLinear
      70             :                                                       ? ScaleRowDown2Linear_NEON
      71             :                                                       : ScaleRowDown2Box_NEON);
      72             :     }
      73             :   }
      74             : #endif
      75             : #if defined(HAS_SCALEROWDOWN2_SSSE3)
      76           0 :   if (TestCpuFlag(kCpuHasSSSE3)) {
      77           0 :     ScaleRowDown2 =
      78             :         filtering == kFilterNone
      79           0 :             ? ScaleRowDown2_Any_SSSE3
      80           0 :             : (filtering == kFilterLinear ? ScaleRowDown2Linear_Any_SSSE3
      81             :                                           : ScaleRowDown2Box_Any_SSSE3);
      82           0 :     if (IS_ALIGNED(dst_width, 16)) {
      83           0 :       ScaleRowDown2 =
      84             :           filtering == kFilterNone
      85           0 :               ? ScaleRowDown2_SSSE3
      86           0 :               : (filtering == kFilterLinear ? ScaleRowDown2Linear_SSSE3
      87             :                                             : ScaleRowDown2Box_SSSE3);
      88             :     }
      89             :   }
      90             : #endif
      91             : #if defined(HAS_SCALEROWDOWN2_AVX2)
      92           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
      93           0 :     ScaleRowDown2 =
      94             :         filtering == kFilterNone
      95           0 :             ? ScaleRowDown2_Any_AVX2
      96           0 :             : (filtering == kFilterLinear ? ScaleRowDown2Linear_Any_AVX2
      97             :                                           : ScaleRowDown2Box_Any_AVX2);
      98           0 :     if (IS_ALIGNED(dst_width, 32)) {
      99           0 :       ScaleRowDown2 = filtering == kFilterNone ? ScaleRowDown2_AVX2
     100             :                                                : (filtering == kFilterLinear
     101           0 :                                                       ? ScaleRowDown2Linear_AVX2
     102             :                                                       : ScaleRowDown2Box_AVX2);
     103             :     }
     104             :   }
     105             : #endif
     106             : #if defined(HAS_SCALEROWDOWN2_DSPR2)
     107             :   if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(src_ptr, 4) &&
     108             :       IS_ALIGNED(src_stride, 4) && IS_ALIGNED(row_stride, 4) &&
     109             :       IS_ALIGNED(dst_ptr, 4) && IS_ALIGNED(dst_stride, 4)) {
     110             :     ScaleRowDown2 = filtering ? ScaleRowDown2Box_DSPR2 : ScaleRowDown2_DSPR2;
     111             :   }
     112             : #endif
     113             : #if defined(HAS_SCALEROWDOWN2_MSA)
     114             :   if (TestCpuFlag(kCpuHasMSA)) {
     115             :     ScaleRowDown2 =
     116             :         filtering == kFilterNone
     117             :             ? ScaleRowDown2_Any_MSA
     118             :             : (filtering == kFilterLinear ? ScaleRowDown2Linear_Any_MSA
     119             :                                           : ScaleRowDown2Box_Any_MSA);
     120             :     if (IS_ALIGNED(dst_width, 32)) {
     121             :       ScaleRowDown2 = filtering == kFilterNone ? ScaleRowDown2_MSA
     122             :                                                : (filtering == kFilterLinear
     123             :                                                       ? ScaleRowDown2Linear_MSA
     124             :                                                       : ScaleRowDown2Box_MSA);
     125             :     }
     126             :   }
     127             : #endif
     128             : 
     129           0 :   if (filtering == kFilterLinear) {
     130           0 :     src_stride = 0;
     131             :   }
     132             :   // TODO(fbarchard): Loop through source height to allow odd height.
     133           0 :   for (y = 0; y < dst_height; ++y) {
     134           0 :     ScaleRowDown2(src_ptr, src_stride, dst_ptr, dst_width);
     135           0 :     src_ptr += row_stride;
     136           0 :     dst_ptr += dst_stride;
     137             :   }
     138           0 : }
     139             : 
     140           0 : static void ScalePlaneDown2_16(int src_width,
     141             :                                int src_height,
     142             :                                int dst_width,
     143             :                                int dst_height,
     144             :                                int src_stride,
     145             :                                int dst_stride,
     146             :                                const uint16* src_ptr,
     147             :                                uint16* dst_ptr,
     148             :                                enum FilterMode filtering) {
     149             :   int y;
     150             :   void (*ScaleRowDown2)(const uint16* src_ptr, ptrdiff_t src_stride,
     151             :                         uint16* dst_ptr, int dst_width) =
     152             :       filtering == kFilterNone
     153           0 :           ? ScaleRowDown2_16_C
     154           0 :           : (filtering == kFilterLinear ? ScaleRowDown2Linear_16_C
     155           0 :                                         : ScaleRowDown2Box_16_C);
     156           0 :   int row_stride = src_stride << 1;
     157             :   (void)src_width;
     158             :   (void)src_height;
     159           0 :   if (!filtering) {
     160           0 :     src_ptr += src_stride;  // Point to odd rows.
     161           0 :     src_stride = 0;
     162             :   }
     163             : 
     164             : #if defined(HAS_SCALEROWDOWN2_16_NEON)
     165             :   if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(dst_width, 16)) {
     166             :     ScaleRowDown2 =
     167             :         filtering ? ScaleRowDown2Box_16_NEON : ScaleRowDown2_16_NEON;
     168             :   }
     169             : #endif
     170             : #if defined(HAS_SCALEROWDOWN2_16_SSE2)
     171             :   if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(dst_width, 16)) {
     172             :     ScaleRowDown2 =
     173             :         filtering == kFilterNone
     174             :             ? ScaleRowDown2_16_SSE2
     175             :             : (filtering == kFilterLinear ? ScaleRowDown2Linear_16_SSE2
     176             :                                           : ScaleRowDown2Box_16_SSE2);
     177             :   }
     178             : #endif
     179             : #if defined(HAS_SCALEROWDOWN2_16_DSPR2)
     180             :   if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(src_ptr, 4) &&
     181             :       IS_ALIGNED(src_stride, 4) && IS_ALIGNED(row_stride, 4) &&
     182             :       IS_ALIGNED(dst_ptr, 4) && IS_ALIGNED(dst_stride, 4)) {
     183             :     ScaleRowDown2 =
     184             :         filtering ? ScaleRowDown2Box_16_DSPR2 : ScaleRowDown2_16_DSPR2;
     185             :   }
     186             : #endif
     187             : 
     188           0 :   if (filtering == kFilterLinear) {
     189           0 :     src_stride = 0;
     190             :   }
     191             :   // TODO(fbarchard): Loop through source height to allow odd height.
     192           0 :   for (y = 0; y < dst_height; ++y) {
     193           0 :     ScaleRowDown2(src_ptr, src_stride, dst_ptr, dst_width);
     194           0 :     src_ptr += row_stride;
     195           0 :     dst_ptr += dst_stride;
     196             :   }
     197           0 : }
     198             : 
     199             : // Scale plane, 1/4
     200             : // This is an optimized version for scaling down a plane to 1/4 of
     201             : // its original size.
     202             : 
     203           0 : static void ScalePlaneDown4(int src_width,
     204             :                             int src_height,
     205             :                             int dst_width,
     206             :                             int dst_height,
     207             :                             int src_stride,
     208             :                             int dst_stride,
     209             :                             const uint8* src_ptr,
     210             :                             uint8* dst_ptr,
     211             :                             enum FilterMode filtering) {
     212             :   int y;
     213             :   void (*ScaleRowDown4)(const uint8* src_ptr, ptrdiff_t src_stride,
     214             :                         uint8* dst_ptr, int dst_width) =
     215           0 :       filtering ? ScaleRowDown4Box_C : ScaleRowDown4_C;
     216           0 :   int row_stride = src_stride << 2;
     217             :   (void)src_width;
     218             :   (void)src_height;
     219           0 :   if (!filtering) {
     220           0 :     src_ptr += src_stride * 2;  // Point to row 2.
     221           0 :     src_stride = 0;
     222             :   }
     223             : #if defined(HAS_SCALEROWDOWN4_NEON)
     224             :   if (TestCpuFlag(kCpuHasNEON)) {
     225             :     ScaleRowDown4 =
     226             :         filtering ? ScaleRowDown4Box_Any_NEON : ScaleRowDown4_Any_NEON;
     227             :     if (IS_ALIGNED(dst_width, 8)) {
     228             :       ScaleRowDown4 = filtering ? ScaleRowDown4Box_NEON : ScaleRowDown4_NEON;
     229             :     }
     230             :   }
     231             : #endif
     232             : #if defined(HAS_SCALEROWDOWN4_SSSE3)
     233           0 :   if (TestCpuFlag(kCpuHasSSSE3)) {
     234           0 :     ScaleRowDown4 =
     235           0 :         filtering ? ScaleRowDown4Box_Any_SSSE3 : ScaleRowDown4_Any_SSSE3;
     236           0 :     if (IS_ALIGNED(dst_width, 8)) {
     237           0 :       ScaleRowDown4 = filtering ? ScaleRowDown4Box_SSSE3 : ScaleRowDown4_SSSE3;
     238             :     }
     239             :   }
     240             : #endif
     241             : #if defined(HAS_SCALEROWDOWN4_AVX2)
     242           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
     243           0 :     ScaleRowDown4 =
     244           0 :         filtering ? ScaleRowDown4Box_Any_AVX2 : ScaleRowDown4_Any_AVX2;
     245           0 :     if (IS_ALIGNED(dst_width, 16)) {
     246           0 :       ScaleRowDown4 = filtering ? ScaleRowDown4Box_AVX2 : ScaleRowDown4_AVX2;
     247             :     }
     248             :   }
     249             : #endif
     250             : #if defined(HAS_SCALEROWDOWN4_DSPR2)
     251             :   if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(row_stride, 4) &&
     252             :       IS_ALIGNED(src_ptr, 4) && IS_ALIGNED(src_stride, 4) &&
     253             :       IS_ALIGNED(dst_ptr, 4) && IS_ALIGNED(dst_stride, 4)) {
     254             :     ScaleRowDown4 = filtering ? ScaleRowDown4Box_DSPR2 : ScaleRowDown4_DSPR2;
     255             :   }
     256             : #endif
     257             : #if defined(HAS_SCALEROWDOWN4_MSA)
     258             :   if (TestCpuFlag(kCpuHasMSA)) {
     259             :     ScaleRowDown4 =
     260             :         filtering ? ScaleRowDown4Box_Any_MSA : ScaleRowDown4_Any_MSA;
     261             :     if (IS_ALIGNED(dst_width, 16)) {
     262             :       ScaleRowDown4 = filtering ? ScaleRowDown4Box_MSA : ScaleRowDown4_MSA;
     263             :     }
     264             :   }
     265             : #endif
     266             : 
     267           0 :   if (filtering == kFilterLinear) {
     268           0 :     src_stride = 0;
     269             :   }
     270           0 :   for (y = 0; y < dst_height; ++y) {
     271           0 :     ScaleRowDown4(src_ptr, src_stride, dst_ptr, dst_width);
     272           0 :     src_ptr += row_stride;
     273           0 :     dst_ptr += dst_stride;
     274             :   }
     275           0 : }
     276             : 
     277           0 : static void ScalePlaneDown4_16(int src_width,
     278             :                                int src_height,
     279             :                                int dst_width,
     280             :                                int dst_height,
     281             :                                int src_stride,
     282             :                                int dst_stride,
     283             :                                const uint16* src_ptr,
     284             :                                uint16* dst_ptr,
     285             :                                enum FilterMode filtering) {
     286             :   int y;
     287             :   void (*ScaleRowDown4)(const uint16* src_ptr, ptrdiff_t src_stride,
     288             :                         uint16* dst_ptr, int dst_width) =
     289           0 :       filtering ? ScaleRowDown4Box_16_C : ScaleRowDown4_16_C;
     290           0 :   int row_stride = src_stride << 2;
     291             :   (void)src_width;
     292             :   (void)src_height;
     293           0 :   if (!filtering) {
     294           0 :     src_ptr += src_stride * 2;  // Point to row 2.
     295           0 :     src_stride = 0;
     296             :   }
     297             : #if defined(HAS_SCALEROWDOWN4_16_NEON)
     298             :   if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(dst_width, 8)) {
     299             :     ScaleRowDown4 =
     300             :         filtering ? ScaleRowDown4Box_16_NEON : ScaleRowDown4_16_NEON;
     301             :   }
     302             : #endif
     303             : #if defined(HAS_SCALEROWDOWN4_16_SSE2)
     304             :   if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(dst_width, 8)) {
     305             :     ScaleRowDown4 =
     306             :         filtering ? ScaleRowDown4Box_16_SSE2 : ScaleRowDown4_16_SSE2;
     307             :   }
     308             : #endif
     309             : #if defined(HAS_SCALEROWDOWN4_16_DSPR2)
     310             :   if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(row_stride, 4) &&
     311             :       IS_ALIGNED(src_ptr, 4) && IS_ALIGNED(src_stride, 4) &&
     312             :       IS_ALIGNED(dst_ptr, 4) && IS_ALIGNED(dst_stride, 4)) {
     313             :     ScaleRowDown4 =
     314             :         filtering ? ScaleRowDown4Box_16_DSPR2 : ScaleRowDown4_16_DSPR2;
     315             :   }
     316             : #endif
     317             : 
     318           0 :   if (filtering == kFilterLinear) {
     319           0 :     src_stride = 0;
     320             :   }
     321           0 :   for (y = 0; y < dst_height; ++y) {
     322           0 :     ScaleRowDown4(src_ptr, src_stride, dst_ptr, dst_width);
     323           0 :     src_ptr += row_stride;
     324           0 :     dst_ptr += dst_stride;
     325             :   }
     326           0 : }
     327             : 
     328             : // Scale plane down, 3/4
     329           0 : static void ScalePlaneDown34(int src_width,
     330             :                              int src_height,
     331             :                              int dst_width,
     332             :                              int dst_height,
     333             :                              int src_stride,
     334             :                              int dst_stride,
     335             :                              const uint8* src_ptr,
     336             :                              uint8* dst_ptr,
     337             :                              enum FilterMode filtering) {
     338             :   int y;
     339             :   void (*ScaleRowDown34_0)(const uint8* src_ptr, ptrdiff_t src_stride,
     340             :                            uint8* dst_ptr, int dst_width);
     341             :   void (*ScaleRowDown34_1)(const uint8* src_ptr, ptrdiff_t src_stride,
     342             :                            uint8* dst_ptr, int dst_width);
     343           0 :   const int filter_stride = (filtering == kFilterLinear) ? 0 : src_stride;
     344             :   (void)src_width;
     345             :   (void)src_height;
     346           0 :   assert(dst_width % 3 == 0);
     347           0 :   if (!filtering) {
     348           0 :     ScaleRowDown34_0 = ScaleRowDown34_C;
     349           0 :     ScaleRowDown34_1 = ScaleRowDown34_C;
     350             :   } else {
     351           0 :     ScaleRowDown34_0 = ScaleRowDown34_0_Box_C;
     352           0 :     ScaleRowDown34_1 = ScaleRowDown34_1_Box_C;
     353             :   }
     354             : #if defined(HAS_SCALEROWDOWN34_NEON)
     355             :   if (TestCpuFlag(kCpuHasNEON)) {
     356             :     if (!filtering) {
     357             :       ScaleRowDown34_0 = ScaleRowDown34_Any_NEON;
     358             :       ScaleRowDown34_1 = ScaleRowDown34_Any_NEON;
     359             :     } else {
     360             :       ScaleRowDown34_0 = ScaleRowDown34_0_Box_Any_NEON;
     361             :       ScaleRowDown34_1 = ScaleRowDown34_1_Box_Any_NEON;
     362             :     }
     363             :     if (dst_width % 24 == 0) {
     364             :       if (!filtering) {
     365             :         ScaleRowDown34_0 = ScaleRowDown34_NEON;
     366             :         ScaleRowDown34_1 = ScaleRowDown34_NEON;
     367             :       } else {
     368             :         ScaleRowDown34_0 = ScaleRowDown34_0_Box_NEON;
     369             :         ScaleRowDown34_1 = ScaleRowDown34_1_Box_NEON;
     370             :       }
     371             :     }
     372             :   }
     373             : #endif
     374             : #if defined(HAS_SCALEROWDOWN34_SSSE3)
     375           0 :   if (TestCpuFlag(kCpuHasSSSE3)) {
     376           0 :     if (!filtering) {
     377           0 :       ScaleRowDown34_0 = ScaleRowDown34_Any_SSSE3;
     378           0 :       ScaleRowDown34_1 = ScaleRowDown34_Any_SSSE3;
     379             :     } else {
     380           0 :       ScaleRowDown34_0 = ScaleRowDown34_0_Box_Any_SSSE3;
     381           0 :       ScaleRowDown34_1 = ScaleRowDown34_1_Box_Any_SSSE3;
     382             :     }
     383           0 :     if (dst_width % 24 == 0) {
     384           0 :       if (!filtering) {
     385           0 :         ScaleRowDown34_0 = ScaleRowDown34_SSSE3;
     386           0 :         ScaleRowDown34_1 = ScaleRowDown34_SSSE3;
     387             :       } else {
     388           0 :         ScaleRowDown34_0 = ScaleRowDown34_0_Box_SSSE3;
     389           0 :         ScaleRowDown34_1 = ScaleRowDown34_1_Box_SSSE3;
     390             :       }
     391             :     }
     392             :   }
     393             : #endif
     394             : #if defined(HAS_SCALEROWDOWN34_DSPR2)
     395             :   if (TestCpuFlag(kCpuHasDSPR2) && (dst_width % 24 == 0) &&
     396             :       IS_ALIGNED(src_ptr, 4) && IS_ALIGNED(src_stride, 4) &&
     397             :       IS_ALIGNED(dst_ptr, 4) && IS_ALIGNED(dst_stride, 4)) {
     398             :     if (!filtering) {
     399             :       ScaleRowDown34_0 = ScaleRowDown34_DSPR2;
     400             :       ScaleRowDown34_1 = ScaleRowDown34_DSPR2;
     401             :     } else {
     402             :       ScaleRowDown34_0 = ScaleRowDown34_0_Box_DSPR2;
     403             :       ScaleRowDown34_1 = ScaleRowDown34_1_Box_DSPR2;
     404             :     }
     405             :   }
     406             : #endif
     407             : 
     408           0 :   for (y = 0; y < dst_height - 2; y += 3) {
     409           0 :     ScaleRowDown34_0(src_ptr, filter_stride, dst_ptr, dst_width);
     410           0 :     src_ptr += src_stride;
     411           0 :     dst_ptr += dst_stride;
     412           0 :     ScaleRowDown34_1(src_ptr, filter_stride, dst_ptr, dst_width);
     413           0 :     src_ptr += src_stride;
     414           0 :     dst_ptr += dst_stride;
     415           0 :     ScaleRowDown34_0(src_ptr + src_stride, -filter_stride, dst_ptr, dst_width);
     416           0 :     src_ptr += src_stride * 2;
     417           0 :     dst_ptr += dst_stride;
     418             :   }
     419             : 
     420             :   // Remainder 1 or 2 rows with last row vertically unfiltered
     421           0 :   if ((dst_height % 3) == 2) {
     422           0 :     ScaleRowDown34_0(src_ptr, filter_stride, dst_ptr, dst_width);
     423           0 :     src_ptr += src_stride;
     424           0 :     dst_ptr += dst_stride;
     425           0 :     ScaleRowDown34_1(src_ptr, 0, dst_ptr, dst_width);
     426           0 :   } else if ((dst_height % 3) == 1) {
     427           0 :     ScaleRowDown34_0(src_ptr, 0, dst_ptr, dst_width);
     428             :   }
     429           0 : }
     430             : 
     431           0 : static void ScalePlaneDown34_16(int src_width,
     432             :                                 int src_height,
     433             :                                 int dst_width,
     434             :                                 int dst_height,
     435             :                                 int src_stride,
     436             :                                 int dst_stride,
     437             :                                 const uint16* src_ptr,
     438             :                                 uint16* dst_ptr,
     439             :                                 enum FilterMode filtering) {
     440             :   int y;
     441             :   void (*ScaleRowDown34_0)(const uint16* src_ptr, ptrdiff_t src_stride,
     442             :                            uint16* dst_ptr, int dst_width);
     443             :   void (*ScaleRowDown34_1)(const uint16* src_ptr, ptrdiff_t src_stride,
     444             :                            uint16* dst_ptr, int dst_width);
     445           0 :   const int filter_stride = (filtering == kFilterLinear) ? 0 : src_stride;
     446             :   (void)src_width;
     447             :   (void)src_height;
     448           0 :   assert(dst_width % 3 == 0);
     449           0 :   if (!filtering) {
     450           0 :     ScaleRowDown34_0 = ScaleRowDown34_16_C;
     451           0 :     ScaleRowDown34_1 = ScaleRowDown34_16_C;
     452             :   } else {
     453           0 :     ScaleRowDown34_0 = ScaleRowDown34_0_Box_16_C;
     454           0 :     ScaleRowDown34_1 = ScaleRowDown34_1_Box_16_C;
     455             :   }
     456             : #if defined(HAS_SCALEROWDOWN34_16_NEON)
     457             :   if (TestCpuFlag(kCpuHasNEON) && (dst_width % 24 == 0)) {
     458             :     if (!filtering) {
     459             :       ScaleRowDown34_0 = ScaleRowDown34_16_NEON;
     460             :       ScaleRowDown34_1 = ScaleRowDown34_16_NEON;
     461             :     } else {
     462             :       ScaleRowDown34_0 = ScaleRowDown34_0_Box_16_NEON;
     463             :       ScaleRowDown34_1 = ScaleRowDown34_1_Box_16_NEON;
     464             :     }
     465             :   }
     466             : #endif
     467             : #if defined(HAS_SCALEROWDOWN34_16_SSSE3)
     468             :   if (TestCpuFlag(kCpuHasSSSE3) && (dst_width % 24 == 0)) {
     469             :     if (!filtering) {
     470             :       ScaleRowDown34_0 = ScaleRowDown34_16_SSSE3;
     471             :       ScaleRowDown34_1 = ScaleRowDown34_16_SSSE3;
     472             :     } else {
     473             :       ScaleRowDown34_0 = ScaleRowDown34_0_Box_16_SSSE3;
     474             :       ScaleRowDown34_1 = ScaleRowDown34_1_Box_16_SSSE3;
     475             :     }
     476             :   }
     477             : #endif
     478             : #if defined(HAS_SCALEROWDOWN34_16_DSPR2)
     479             :   if (TestCpuFlag(kCpuHasDSPR2) && (dst_width % 24 == 0) &&
     480             :       IS_ALIGNED(src_ptr, 4) && IS_ALIGNED(src_stride, 4) &&
     481             :       IS_ALIGNED(dst_ptr, 4) && IS_ALIGNED(dst_stride, 4)) {
     482             :     if (!filtering) {
     483             :       ScaleRowDown34_0 = ScaleRowDown34_16_DSPR2;
     484             :       ScaleRowDown34_1 = ScaleRowDown34_16_DSPR2;
     485             :     } else {
     486             :       ScaleRowDown34_0 = ScaleRowDown34_0_Box_16_DSPR2;
     487             :       ScaleRowDown34_1 = ScaleRowDown34_1_Box_16_DSPR2;
     488             :     }
     489             :   }
     490             : #endif
     491             : 
     492           0 :   for (y = 0; y < dst_height - 2; y += 3) {
     493           0 :     ScaleRowDown34_0(src_ptr, filter_stride, dst_ptr, dst_width);
     494           0 :     src_ptr += src_stride;
     495           0 :     dst_ptr += dst_stride;
     496           0 :     ScaleRowDown34_1(src_ptr, filter_stride, dst_ptr, dst_width);
     497           0 :     src_ptr += src_stride;
     498           0 :     dst_ptr += dst_stride;
     499           0 :     ScaleRowDown34_0(src_ptr + src_stride, -filter_stride, dst_ptr, dst_width);
     500           0 :     src_ptr += src_stride * 2;
     501           0 :     dst_ptr += dst_stride;
     502             :   }
     503             : 
     504             :   // Remainder 1 or 2 rows with last row vertically unfiltered
     505           0 :   if ((dst_height % 3) == 2) {
     506           0 :     ScaleRowDown34_0(src_ptr, filter_stride, dst_ptr, dst_width);
     507           0 :     src_ptr += src_stride;
     508           0 :     dst_ptr += dst_stride;
     509           0 :     ScaleRowDown34_1(src_ptr, 0, dst_ptr, dst_width);
     510           0 :   } else if ((dst_height % 3) == 1) {
     511           0 :     ScaleRowDown34_0(src_ptr, 0, dst_ptr, dst_width);
     512             :   }
     513           0 : }
     514             : 
     515             : // Scale plane, 3/8
     516             : // This is an optimized version for scaling down a plane to 3/8
     517             : // of its original size.
     518             : //
     519             : // Uses box filter arranges like this
     520             : // aaabbbcc -> abc
     521             : // aaabbbcc    def
     522             : // aaabbbcc    ghi
     523             : // dddeeeff
     524             : // dddeeeff
     525             : // dddeeeff
     526             : // ggghhhii
     527             : // ggghhhii
     528             : // Boxes are 3x3, 2x3, 3x2 and 2x2
     529             : 
     530           0 : static void ScalePlaneDown38(int src_width,
     531             :                              int src_height,
     532             :                              int dst_width,
     533             :                              int dst_height,
     534             :                              int src_stride,
     535             :                              int dst_stride,
     536             :                              const uint8* src_ptr,
     537             :                              uint8* dst_ptr,
     538             :                              enum FilterMode filtering) {
     539             :   int y;
     540             :   void (*ScaleRowDown38_3)(const uint8* src_ptr, ptrdiff_t src_stride,
     541             :                            uint8* dst_ptr, int dst_width);
     542             :   void (*ScaleRowDown38_2)(const uint8* src_ptr, ptrdiff_t src_stride,
     543             :                            uint8* dst_ptr, int dst_width);
     544           0 :   const int filter_stride = (filtering == kFilterLinear) ? 0 : src_stride;
     545           0 :   assert(dst_width % 3 == 0);
     546             :   (void)src_width;
     547             :   (void)src_height;
     548           0 :   if (!filtering) {
     549           0 :     ScaleRowDown38_3 = ScaleRowDown38_C;
     550           0 :     ScaleRowDown38_2 = ScaleRowDown38_C;
     551             :   } else {
     552           0 :     ScaleRowDown38_3 = ScaleRowDown38_3_Box_C;
     553           0 :     ScaleRowDown38_2 = ScaleRowDown38_2_Box_C;
     554             :   }
     555             : 
     556             : #if defined(HAS_SCALEROWDOWN38_NEON)
     557             :   if (TestCpuFlag(kCpuHasNEON)) {
     558             :     if (!filtering) {
     559             :       ScaleRowDown38_3 = ScaleRowDown38_Any_NEON;
     560             :       ScaleRowDown38_2 = ScaleRowDown38_Any_NEON;
     561             :     } else {
     562             :       ScaleRowDown38_3 = ScaleRowDown38_3_Box_Any_NEON;
     563             :       ScaleRowDown38_2 = ScaleRowDown38_2_Box_Any_NEON;
     564             :     }
     565             :     if (dst_width % 12 == 0) {
     566             :       if (!filtering) {
     567             :         ScaleRowDown38_3 = ScaleRowDown38_NEON;
     568             :         ScaleRowDown38_2 = ScaleRowDown38_NEON;
     569             :       } else {
     570             :         ScaleRowDown38_3 = ScaleRowDown38_3_Box_NEON;
     571             :         ScaleRowDown38_2 = ScaleRowDown38_2_Box_NEON;
     572             :       }
     573             :     }
     574             :   }
     575             : #endif
     576             : #if defined(HAS_SCALEROWDOWN38_SSSE3)
     577           0 :   if (TestCpuFlag(kCpuHasSSSE3)) {
     578           0 :     if (!filtering) {
     579           0 :       ScaleRowDown38_3 = ScaleRowDown38_Any_SSSE3;
     580           0 :       ScaleRowDown38_2 = ScaleRowDown38_Any_SSSE3;
     581             :     } else {
     582           0 :       ScaleRowDown38_3 = ScaleRowDown38_3_Box_Any_SSSE3;
     583           0 :       ScaleRowDown38_2 = ScaleRowDown38_2_Box_Any_SSSE3;
     584             :     }
     585           0 :     if (dst_width % 12 == 0 && !filtering) {
     586           0 :       ScaleRowDown38_3 = ScaleRowDown38_SSSE3;
     587           0 :       ScaleRowDown38_2 = ScaleRowDown38_SSSE3;
     588             :     }
     589           0 :     if (dst_width % 6 == 0 && filtering) {
     590           0 :       ScaleRowDown38_3 = ScaleRowDown38_3_Box_SSSE3;
     591           0 :       ScaleRowDown38_2 = ScaleRowDown38_2_Box_SSSE3;
     592             :     }
     593             :   }
     594             : #endif
     595             : #if defined(HAS_SCALEROWDOWN38_DSPR2)
     596             :   if (TestCpuFlag(kCpuHasDSPR2) && (dst_width % 12 == 0) &&
     597             :       IS_ALIGNED(src_ptr, 4) && IS_ALIGNED(src_stride, 4) &&
     598             :       IS_ALIGNED(dst_ptr, 4) && IS_ALIGNED(dst_stride, 4)) {
     599             :     if (!filtering) {
     600             :       ScaleRowDown38_3 = ScaleRowDown38_DSPR2;
     601             :       ScaleRowDown38_2 = ScaleRowDown38_DSPR2;
     602             :     } else {
     603             :       ScaleRowDown38_3 = ScaleRowDown38_3_Box_DSPR2;
     604             :       ScaleRowDown38_2 = ScaleRowDown38_2_Box_DSPR2;
     605             :     }
     606             :   }
     607             : #endif
     608             : #if defined(HAS_SCALEROWDOWN38_MSA)
     609             :   if (TestCpuFlag(kCpuHasMSA)) {
     610             :     if (!filtering) {
     611             :       ScaleRowDown38_3 = ScaleRowDown38_Any_MSA;
     612             :       ScaleRowDown38_2 = ScaleRowDown38_Any_MSA;
     613             :     } else {
     614             :       ScaleRowDown38_3 = ScaleRowDown38_3_Box_Any_MSA;
     615             :       ScaleRowDown38_2 = ScaleRowDown38_2_Box_Any_MSA;
     616             :     }
     617             :     if (dst_width % 12 == 0) {
     618             :       if (!filtering) {
     619             :         ScaleRowDown38_3 = ScaleRowDown38_MSA;
     620             :         ScaleRowDown38_2 = ScaleRowDown38_MSA;
     621             :       } else {
     622             :         ScaleRowDown38_3 = ScaleRowDown38_3_Box_MSA;
     623             :         ScaleRowDown38_2 = ScaleRowDown38_2_Box_MSA;
     624             :       }
     625             :     }
     626             :   }
     627             : #endif
     628             : 
     629           0 :   for (y = 0; y < dst_height - 2; y += 3) {
     630           0 :     ScaleRowDown38_3(src_ptr, filter_stride, dst_ptr, dst_width);
     631           0 :     src_ptr += src_stride * 3;
     632           0 :     dst_ptr += dst_stride;
     633           0 :     ScaleRowDown38_3(src_ptr, filter_stride, dst_ptr, dst_width);
     634           0 :     src_ptr += src_stride * 3;
     635           0 :     dst_ptr += dst_stride;
     636           0 :     ScaleRowDown38_2(src_ptr, filter_stride, dst_ptr, dst_width);
     637           0 :     src_ptr += src_stride * 2;
     638           0 :     dst_ptr += dst_stride;
     639             :   }
     640             : 
     641             :   // Remainder 1 or 2 rows with last row vertically unfiltered
     642           0 :   if ((dst_height % 3) == 2) {
     643           0 :     ScaleRowDown38_3(src_ptr, filter_stride, dst_ptr, dst_width);
     644           0 :     src_ptr += src_stride * 3;
     645           0 :     dst_ptr += dst_stride;
     646           0 :     ScaleRowDown38_3(src_ptr, 0, dst_ptr, dst_width);
     647           0 :   } else if ((dst_height % 3) == 1) {
     648           0 :     ScaleRowDown38_3(src_ptr, 0, dst_ptr, dst_width);
     649             :   }
     650           0 : }
     651             : 
     652           0 : static void ScalePlaneDown38_16(int src_width,
     653             :                                 int src_height,
     654             :                                 int dst_width,
     655             :                                 int dst_height,
     656             :                                 int src_stride,
     657             :                                 int dst_stride,
     658             :                                 const uint16* src_ptr,
     659             :                                 uint16* dst_ptr,
     660             :                                 enum FilterMode filtering) {
     661             :   int y;
     662             :   void (*ScaleRowDown38_3)(const uint16* src_ptr, ptrdiff_t src_stride,
     663             :                            uint16* dst_ptr, int dst_width);
     664             :   void (*ScaleRowDown38_2)(const uint16* src_ptr, ptrdiff_t src_stride,
     665             :                            uint16* dst_ptr, int dst_width);
     666           0 :   const int filter_stride = (filtering == kFilterLinear) ? 0 : src_stride;
     667             :   (void)src_width;
     668             :   (void)src_height;
     669           0 :   assert(dst_width % 3 == 0);
     670           0 :   if (!filtering) {
     671           0 :     ScaleRowDown38_3 = ScaleRowDown38_16_C;
     672           0 :     ScaleRowDown38_2 = ScaleRowDown38_16_C;
     673             :   } else {
     674           0 :     ScaleRowDown38_3 = ScaleRowDown38_3_Box_16_C;
     675           0 :     ScaleRowDown38_2 = ScaleRowDown38_2_Box_16_C;
     676             :   }
     677             : #if defined(HAS_SCALEROWDOWN38_16_NEON)
     678             :   if (TestCpuFlag(kCpuHasNEON) && (dst_width % 12 == 0)) {
     679             :     if (!filtering) {
     680             :       ScaleRowDown38_3 = ScaleRowDown38_16_NEON;
     681             :       ScaleRowDown38_2 = ScaleRowDown38_16_NEON;
     682             :     } else {
     683             :       ScaleRowDown38_3 = ScaleRowDown38_3_Box_16_NEON;
     684             :       ScaleRowDown38_2 = ScaleRowDown38_2_Box_16_NEON;
     685             :     }
     686             :   }
     687             : #endif
     688             : #if defined(HAS_SCALEROWDOWN38_16_SSSE3)
     689             :   if (TestCpuFlag(kCpuHasSSSE3) && (dst_width % 24 == 0)) {
     690             :     if (!filtering) {
     691             :       ScaleRowDown38_3 = ScaleRowDown38_16_SSSE3;
     692             :       ScaleRowDown38_2 = ScaleRowDown38_16_SSSE3;
     693             :     } else {
     694             :       ScaleRowDown38_3 = ScaleRowDown38_3_Box_16_SSSE3;
     695             :       ScaleRowDown38_2 = ScaleRowDown38_2_Box_16_SSSE3;
     696             :     }
     697             :   }
     698             : #endif
     699             : #if defined(HAS_SCALEROWDOWN38_16_DSPR2)
     700             :   if (TestCpuFlag(kCpuHasDSPR2) && (dst_width % 12 == 0) &&
     701             :       IS_ALIGNED(src_ptr, 4) && IS_ALIGNED(src_stride, 4) &&
     702             :       IS_ALIGNED(dst_ptr, 4) && IS_ALIGNED(dst_stride, 4)) {
     703             :     if (!filtering) {
     704             :       ScaleRowDown38_3 = ScaleRowDown38_16_DSPR2;
     705             :       ScaleRowDown38_2 = ScaleRowDown38_16_DSPR2;
     706             :     } else {
     707             :       ScaleRowDown38_3 = ScaleRowDown38_3_Box_16_DSPR2;
     708             :       ScaleRowDown38_2 = ScaleRowDown38_2_Box_16_DSPR2;
     709             :     }
     710             :   }
     711             : #endif
     712             : 
     713           0 :   for (y = 0; y < dst_height - 2; y += 3) {
     714           0 :     ScaleRowDown38_3(src_ptr, filter_stride, dst_ptr, dst_width);
     715           0 :     src_ptr += src_stride * 3;
     716           0 :     dst_ptr += dst_stride;
     717           0 :     ScaleRowDown38_3(src_ptr, filter_stride, dst_ptr, dst_width);
     718           0 :     src_ptr += src_stride * 3;
     719           0 :     dst_ptr += dst_stride;
     720           0 :     ScaleRowDown38_2(src_ptr, filter_stride, dst_ptr, dst_width);
     721           0 :     src_ptr += src_stride * 2;
     722           0 :     dst_ptr += dst_stride;
     723             :   }
     724             : 
     725             :   // Remainder 1 or 2 rows with last row vertically unfiltered
     726           0 :   if ((dst_height % 3) == 2) {
     727           0 :     ScaleRowDown38_3(src_ptr, filter_stride, dst_ptr, dst_width);
     728           0 :     src_ptr += src_stride * 3;
     729           0 :     dst_ptr += dst_stride;
     730           0 :     ScaleRowDown38_3(src_ptr, 0, dst_ptr, dst_width);
     731           0 :   } else if ((dst_height % 3) == 1) {
     732           0 :     ScaleRowDown38_3(src_ptr, 0, dst_ptr, dst_width);
     733             :   }
     734           0 : }
     735             : 
     736             : #define MIN1(x) ((x) < 1 ? 1 : (x))
     737             : 
     738           0 : static __inline uint32 SumPixels(int iboxwidth, const uint16* src_ptr) {
     739           0 :   uint32 sum = 0u;
     740             :   int x;
     741           0 :   assert(iboxwidth > 0);
     742           0 :   for (x = 0; x < iboxwidth; ++x) {
     743           0 :     sum += src_ptr[x];
     744             :   }
     745           0 :   return sum;
     746             : }
     747             : 
     748           0 : static __inline uint32 SumPixels_16(int iboxwidth, const uint32* src_ptr) {
     749           0 :   uint32 sum = 0u;
     750             :   int x;
     751           0 :   assert(iboxwidth > 0);
     752           0 :   for (x = 0; x < iboxwidth; ++x) {
     753           0 :     sum += src_ptr[x];
     754             :   }
     755           0 :   return sum;
     756             : }
     757             : 
     758           0 : static void ScaleAddCols2_C(int dst_width,
     759             :                             int boxheight,
     760             :                             int x,
     761             :                             int dx,
     762             :                             const uint16* src_ptr,
     763             :                             uint8* dst_ptr) {
     764             :   int i;
     765             :   int scaletbl[2];
     766           0 :   int minboxwidth = dx >> 16;
     767             :   int boxwidth;
     768           0 :   scaletbl[0] = 65536 / (MIN1(minboxwidth) * boxheight);
     769           0 :   scaletbl[1] = 65536 / (MIN1(minboxwidth + 1) * boxheight);
     770           0 :   for (i = 0; i < dst_width; ++i) {
     771           0 :     int ix = x >> 16;
     772           0 :     x += dx;
     773           0 :     boxwidth = MIN1((x >> 16) - ix);
     774           0 :     *dst_ptr++ =
     775           0 :         SumPixels(boxwidth, src_ptr + ix) * scaletbl[boxwidth - minboxwidth] >>
     776           0 :         16;
     777             :   }
     778           0 : }
     779             : 
     780           0 : static void ScaleAddCols2_16_C(int dst_width,
     781             :                                int boxheight,
     782             :                                int x,
     783             :                                int dx,
     784             :                                const uint32* src_ptr,
     785             :                                uint16* dst_ptr) {
     786             :   int i;
     787             :   int scaletbl[2];
     788           0 :   int minboxwidth = dx >> 16;
     789             :   int boxwidth;
     790           0 :   scaletbl[0] = 65536 / (MIN1(minboxwidth) * boxheight);
     791           0 :   scaletbl[1] = 65536 / (MIN1(minboxwidth + 1) * boxheight);
     792           0 :   for (i = 0; i < dst_width; ++i) {
     793           0 :     int ix = x >> 16;
     794           0 :     x += dx;
     795           0 :     boxwidth = MIN1((x >> 16) - ix);
     796           0 :     *dst_ptr++ = SumPixels_16(boxwidth, src_ptr + ix) *
     797           0 :                      scaletbl[boxwidth - minboxwidth] >>
     798           0 :                  16;
     799             :   }
     800           0 : }
     801             : 
     802           0 : static void ScaleAddCols0_C(int dst_width,
     803             :                             int boxheight,
     804             :                             int x,
     805             :                             int,
     806             :                             const uint16* src_ptr,
     807             :                             uint8* dst_ptr) {
     808           0 :   int scaleval = 65536 / boxheight;
     809             :   int i;
     810           0 :   src_ptr += (x >> 16);
     811           0 :   for (i = 0; i < dst_width; ++i) {
     812           0 :     *dst_ptr++ = src_ptr[i] * scaleval >> 16;
     813             :   }
     814           0 : }
     815             : 
     816           0 : static void ScaleAddCols1_C(int dst_width,
     817             :                             int boxheight,
     818             :                             int x,
     819             :                             int dx,
     820             :                             const uint16* src_ptr,
     821             :                             uint8* dst_ptr) {
     822           0 :   int boxwidth = MIN1(dx >> 16);
     823           0 :   int scaleval = 65536 / (boxwidth * boxheight);
     824             :   int i;
     825           0 :   x >>= 16;
     826           0 :   for (i = 0; i < dst_width; ++i) {
     827           0 :     *dst_ptr++ = SumPixels(boxwidth, src_ptr + x) * scaleval >> 16;
     828           0 :     x += boxwidth;
     829             :   }
     830           0 : }
     831             : 
     832           0 : static void ScaleAddCols1_16_C(int dst_width,
     833             :                                int boxheight,
     834             :                                int x,
     835             :                                int dx,
     836             :                                const uint32* src_ptr,
     837             :                                uint16* dst_ptr) {
     838           0 :   int boxwidth = MIN1(dx >> 16);
     839           0 :   int scaleval = 65536 / (boxwidth * boxheight);
     840             :   int i;
     841           0 :   for (i = 0; i < dst_width; ++i) {
     842           0 :     *dst_ptr++ = SumPixels_16(boxwidth, src_ptr + x) * scaleval >> 16;
     843           0 :     x += boxwidth;
     844             :   }
     845           0 : }
     846             : 
     847             : // Scale plane down to any dimensions, with interpolation.
     848             : // (boxfilter).
     849             : //
     850             : // Same method as SimpleScale, which is fixed point, outputting
     851             : // one pixel of destination using fixed point (16.16) to step
     852             : // through source, sampling a box of pixel with simple
     853             : // averaging.
     854           0 : static void ScalePlaneBox(int src_width,
     855             :                           int src_height,
     856             :                           int dst_width,
     857             :                           int dst_height,
     858             :                           int src_stride,
     859             :                           int dst_stride,
     860             :                           const uint8* src_ptr,
     861             :                           uint8* dst_ptr) {
     862             :   int j, k;
     863             :   // Initial source x/y coordinate and step values as 16.16 fixed point.
     864           0 :   int x = 0;
     865           0 :   int y = 0;
     866           0 :   int dx = 0;
     867           0 :   int dy = 0;
     868           0 :   const int max_y = (src_height << 16);
     869             :   ScaleSlope(src_width, src_height, dst_width, dst_height, kFilterBox, &x, &y,
     870           0 :              &dx, &dy);
     871           0 :   src_width = Abs(src_width);
     872             :   {
     873             :     // Allocate a row buffer of uint16.
     874           0 :     align_buffer_64(row16, src_width * 2);
     875             :     void (*ScaleAddCols)(int dst_width, int boxheight, int x, int dx,
     876             :                          const uint16* src_ptr, uint8* dst_ptr) =
     877           0 :         (dx & 0xffff) ? ScaleAddCols2_C
     878           0 :                       : ((dx != 0x10000) ? ScaleAddCols1_C : ScaleAddCols0_C);
     879             :     void (*ScaleAddRow)(const uint8* src_ptr, uint16* dst_ptr, int src_width) =
     880           0 :         ScaleAddRow_C;
     881             : #if defined(HAS_SCALEADDROW_SSE2)
     882           0 :     if (TestCpuFlag(kCpuHasSSE2)) {
     883           0 :       ScaleAddRow = ScaleAddRow_Any_SSE2;
     884           0 :       if (IS_ALIGNED(src_width, 16)) {
     885           0 :         ScaleAddRow = ScaleAddRow_SSE2;
     886             :       }
     887             :     }
     888             : #endif
     889             : #if defined(HAS_SCALEADDROW_AVX2)
     890           0 :     if (TestCpuFlag(kCpuHasAVX2)) {
     891           0 :       ScaleAddRow = ScaleAddRow_Any_AVX2;
     892           0 :       if (IS_ALIGNED(src_width, 32)) {
     893           0 :         ScaleAddRow = ScaleAddRow_AVX2;
     894             :       }
     895             :     }
     896             : #endif
     897             : #if defined(HAS_SCALEADDROW_NEON)
     898             :     if (TestCpuFlag(kCpuHasNEON)) {
     899             :       ScaleAddRow = ScaleAddRow_Any_NEON;
     900             :       if (IS_ALIGNED(src_width, 16)) {
     901             :         ScaleAddRow = ScaleAddRow_NEON;
     902             :       }
     903             :     }
     904             : #endif
     905             : #if defined(HAS_SCALEADDROW_MSA)
     906             :     if (TestCpuFlag(kCpuHasMSA)) {
     907             :       ScaleAddRow = ScaleAddRow_Any_MSA;
     908             :       if (IS_ALIGNED(src_width, 16)) {
     909             :         ScaleAddRow = ScaleAddRow_MSA;
     910             :       }
     911             :     }
     912             : #endif
     913             : #if defined(HAS_SCALEADDROW_DSPR2)
     914             :     if (TestCpuFlag(kCpuHasDSPR2)) {
     915             :       ScaleAddRow = ScaleAddRow_Any_DSPR2;
     916             :       if (IS_ALIGNED(src_width, 16)) {
     917             :         ScaleAddRow = ScaleAddRow_DSPR2;
     918             :       }
     919             :     }
     920             : #endif
     921             : 
     922           0 :     for (j = 0; j < dst_height; ++j) {
     923             :       int boxheight;
     924           0 :       int iy = y >> 16;
     925           0 :       const uint8* src = src_ptr + iy * src_stride;
     926           0 :       y += dy;
     927           0 :       if (y > max_y) {
     928           0 :         y = max_y;
     929             :       }
     930           0 :       boxheight = MIN1((y >> 16) - iy);
     931           0 :       memset(row16, 0, src_width * 2);
     932           0 :       for (k = 0; k < boxheight; ++k) {
     933           0 :         ScaleAddRow(src, (uint16*)(row16), src_width);
     934           0 :         src += src_stride;
     935             :       }
     936           0 :       ScaleAddCols(dst_width, boxheight, x, dx, (uint16*)(row16), dst_ptr);
     937           0 :       dst_ptr += dst_stride;
     938             :     }
     939           0 :     free_aligned_buffer_64(row16);
     940             :   }
     941           0 : }
     942             : 
     943           0 : static void ScalePlaneBox_16(int src_width,
     944             :                              int src_height,
     945             :                              int dst_width,
     946             :                              int dst_height,
     947             :                              int src_stride,
     948             :                              int dst_stride,
     949             :                              const uint16* src_ptr,
     950             :                              uint16* dst_ptr) {
     951             :   int j, k;
     952             :   // Initial source x/y coordinate and step values as 16.16 fixed point.
     953           0 :   int x = 0;
     954           0 :   int y = 0;
     955           0 :   int dx = 0;
     956           0 :   int dy = 0;
     957           0 :   const int max_y = (src_height << 16);
     958             :   ScaleSlope(src_width, src_height, dst_width, dst_height, kFilterBox, &x, &y,
     959           0 :              &dx, &dy);
     960           0 :   src_width = Abs(src_width);
     961             :   {
     962             :     // Allocate a row buffer of uint32.
     963           0 :     align_buffer_64(row32, src_width * 4);
     964             :     void (*ScaleAddCols)(int dst_width, int boxheight, int x, int dx,
     965             :                          const uint32* src_ptr, uint16* dst_ptr) =
     966           0 :         (dx & 0xffff) ? ScaleAddCols2_16_C : ScaleAddCols1_16_C;
     967             :     void (*ScaleAddRow)(const uint16* src_ptr, uint32* dst_ptr, int src_width) =
     968           0 :         ScaleAddRow_16_C;
     969             : 
     970             : #if defined(HAS_SCALEADDROW_16_SSE2)
     971             :     if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(src_width, 16)) {
     972             :       ScaleAddRow = ScaleAddRow_16_SSE2;
     973             :     }
     974             : #endif
     975             : 
     976           0 :     for (j = 0; j < dst_height; ++j) {
     977             :       int boxheight;
     978           0 :       int iy = y >> 16;
     979           0 :       const uint16* src = src_ptr + iy * src_stride;
     980           0 :       y += dy;
     981           0 :       if (y > max_y) {
     982           0 :         y = max_y;
     983             :       }
     984           0 :       boxheight = MIN1((y >> 16) - iy);
     985           0 :       memset(row32, 0, src_width * 4);
     986           0 :       for (k = 0; k < boxheight; ++k) {
     987           0 :         ScaleAddRow(src, (uint32*)(row32), src_width);
     988           0 :         src += src_stride;
     989             :       }
     990           0 :       ScaleAddCols(dst_width, boxheight, x, dx, (uint32*)(row32), dst_ptr);
     991           0 :       dst_ptr += dst_stride;
     992             :     }
     993           0 :     free_aligned_buffer_64(row32);
     994             :   }
     995           0 : }
     996             : 
     997             : // Scale plane down with bilinear interpolation.
     998           0 : void ScalePlaneBilinearDown(int src_width,
     999             :                             int src_height,
    1000             :                             int dst_width,
    1001             :                             int dst_height,
    1002             :                             int src_stride,
    1003             :                             int dst_stride,
    1004             :                             const uint8* src_ptr,
    1005             :                             uint8* dst_ptr,
    1006             :                             enum FilterMode filtering) {
    1007             :   // Initial source x/y coordinate and step values as 16.16 fixed point.
    1008           0 :   int x = 0;
    1009           0 :   int y = 0;
    1010           0 :   int dx = 0;
    1011           0 :   int dy = 0;
    1012             :   // TODO(fbarchard): Consider not allocating row buffer for kFilterLinear.
    1013             :   // Allocate a row buffer.
    1014           0 :   align_buffer_64(row, src_width);
    1015             : 
    1016           0 :   const int max_y = (src_height - 1) << 16;
    1017             :   int j;
    1018             :   void (*ScaleFilterCols)(uint8 * dst_ptr, const uint8* src_ptr, int dst_width,
    1019             :                           int x, int dx) =
    1020           0 :       (src_width >= 32768) ? ScaleFilterCols64_C : ScaleFilterCols_C;
    1021             :   void (*InterpolateRow)(uint8 * dst_ptr, const uint8* src_ptr,
    1022             :                          ptrdiff_t src_stride, int dst_width,
    1023           0 :                          int source_y_fraction) = InterpolateRow_C;
    1024             :   ScaleSlope(src_width, src_height, dst_width, dst_height, filtering, &x, &y,
    1025           0 :              &dx, &dy);
    1026           0 :   src_width = Abs(src_width);
    1027             : 
    1028             : #if defined(HAS_INTERPOLATEROW_SSSE3)
    1029           0 :   if (TestCpuFlag(kCpuHasSSSE3)) {
    1030           0 :     InterpolateRow = InterpolateRow_Any_SSSE3;
    1031           0 :     if (IS_ALIGNED(src_width, 16)) {
    1032           0 :       InterpolateRow = InterpolateRow_SSSE3;
    1033             :     }
    1034             :   }
    1035             : #endif
    1036             : #if defined(HAS_INTERPOLATEROW_AVX2)
    1037           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
    1038           0 :     InterpolateRow = InterpolateRow_Any_AVX2;
    1039           0 :     if (IS_ALIGNED(src_width, 32)) {
    1040           0 :       InterpolateRow = InterpolateRow_AVX2;
    1041             :     }
    1042             :   }
    1043             : #endif
    1044             : #if defined(HAS_INTERPOLATEROW_NEON)
    1045             :   if (TestCpuFlag(kCpuHasNEON)) {
    1046             :     InterpolateRow = InterpolateRow_Any_NEON;
    1047             :     if (IS_ALIGNED(src_width, 16)) {
    1048             :       InterpolateRow = InterpolateRow_NEON;
    1049             :     }
    1050             :   }
    1051             : #endif
    1052             : #if defined(HAS_INTERPOLATEROW_DSPR2)
    1053             :   if (TestCpuFlag(kCpuHasDSPR2)) {
    1054             :     InterpolateRow = InterpolateRow_Any_DSPR2;
    1055             :     if (IS_ALIGNED(src_width, 4)) {
    1056             :       InterpolateRow = InterpolateRow_DSPR2;
    1057             :     }
    1058             :   }
    1059             : #endif
    1060             : 
    1061             : #if defined(HAS_SCALEFILTERCOLS_SSSE3)
    1062           0 :   if (TestCpuFlag(kCpuHasSSSE3) && src_width < 32768) {
    1063           0 :     ScaleFilterCols = ScaleFilterCols_SSSE3;
    1064             :   }
    1065             : #endif
    1066             : #if defined(HAS_SCALEFILTERCOLS_NEON)
    1067             :   if (TestCpuFlag(kCpuHasNEON) && src_width < 32768) {
    1068             :     ScaleFilterCols = ScaleFilterCols_Any_NEON;
    1069             :     if (IS_ALIGNED(dst_width, 8)) {
    1070             :       ScaleFilterCols = ScaleFilterCols_NEON;
    1071             :     }
    1072             :   }
    1073             : #endif
    1074           0 :   if (y > max_y) {
    1075           0 :     y = max_y;
    1076             :   }
    1077             : 
    1078           0 :   for (j = 0; j < dst_height; ++j) {
    1079           0 :     int yi = y >> 16;
    1080           0 :     const uint8* src = src_ptr + yi * src_stride;
    1081           0 :     if (filtering == kFilterLinear) {
    1082           0 :       ScaleFilterCols(dst_ptr, src, dst_width, x, dx);
    1083             :     } else {
    1084           0 :       int yf = (y >> 8) & 255;
    1085           0 :       InterpolateRow(row, src, src_stride, src_width, yf);
    1086           0 :       ScaleFilterCols(dst_ptr, row, dst_width, x, dx);
    1087             :     }
    1088           0 :     dst_ptr += dst_stride;
    1089           0 :     y += dy;
    1090           0 :     if (y > max_y) {
    1091           0 :       y = max_y;
    1092             :     }
    1093             :   }
    1094           0 :   free_aligned_buffer_64(row);
    1095           0 : }
    1096             : 
    1097           0 : void ScalePlaneBilinearDown_16(int src_width,
    1098             :                                int src_height,
    1099             :                                int dst_width,
    1100             :                                int dst_height,
    1101             :                                int src_stride,
    1102             :                                int dst_stride,
    1103             :                                const uint16* src_ptr,
    1104             :                                uint16* dst_ptr,
    1105             :                                enum FilterMode filtering) {
    1106             :   // Initial source x/y coordinate and step values as 16.16 fixed point.
    1107           0 :   int x = 0;
    1108           0 :   int y = 0;
    1109           0 :   int dx = 0;
    1110           0 :   int dy = 0;
    1111             :   // TODO(fbarchard): Consider not allocating row buffer for kFilterLinear.
    1112             :   // Allocate a row buffer.
    1113           0 :   align_buffer_64(row, src_width * 2);
    1114             : 
    1115           0 :   const int max_y = (src_height - 1) << 16;
    1116             :   int j;
    1117             :   void (*ScaleFilterCols)(uint16 * dst_ptr, const uint16* src_ptr,
    1118             :                           int dst_width, int x, int dx) =
    1119           0 :       (src_width >= 32768) ? ScaleFilterCols64_16_C : ScaleFilterCols_16_C;
    1120             :   void (*InterpolateRow)(uint16 * dst_ptr, const uint16* src_ptr,
    1121             :                          ptrdiff_t src_stride, int dst_width,
    1122           0 :                          int source_y_fraction) = InterpolateRow_16_C;
    1123             :   ScaleSlope(src_width, src_height, dst_width, dst_height, filtering, &x, &y,
    1124           0 :              &dx, &dy);
    1125           0 :   src_width = Abs(src_width);
    1126             : 
    1127             : #if defined(HAS_INTERPOLATEROW_16_SSE2)
    1128             :   if (TestCpuFlag(kCpuHasSSE2)) {
    1129             :     InterpolateRow = InterpolateRow_Any_16_SSE2;
    1130             :     if (IS_ALIGNED(src_width, 16)) {
    1131             :       InterpolateRow = InterpolateRow_16_SSE2;
    1132             :     }
    1133             :   }
    1134             : #endif
    1135             : #if defined(HAS_INTERPOLATEROW_16_SSSE3)
    1136             :   if (TestCpuFlag(kCpuHasSSSE3)) {
    1137             :     InterpolateRow = InterpolateRow_Any_16_SSSE3;
    1138             :     if (IS_ALIGNED(src_width, 16)) {
    1139             :       InterpolateRow = InterpolateRow_16_SSSE3;
    1140             :     }
    1141             :   }
    1142             : #endif
    1143             : #if defined(HAS_INTERPOLATEROW_16_AVX2)
    1144             :   if (TestCpuFlag(kCpuHasAVX2)) {
    1145             :     InterpolateRow = InterpolateRow_Any_16_AVX2;
    1146             :     if (IS_ALIGNED(src_width, 32)) {
    1147             :       InterpolateRow = InterpolateRow_16_AVX2;
    1148             :     }
    1149             :   }
    1150             : #endif
    1151             : #if defined(HAS_INTERPOLATEROW_16_NEON)
    1152             :   if (TestCpuFlag(kCpuHasNEON)) {
    1153             :     InterpolateRow = InterpolateRow_Any_16_NEON;
    1154             :     if (IS_ALIGNED(src_width, 16)) {
    1155             :       InterpolateRow = InterpolateRow_16_NEON;
    1156             :     }
    1157             :   }
    1158             : #endif
    1159             : #if defined(HAS_INTERPOLATEROW_16_DSPR2)
    1160             :   if (TestCpuFlag(kCpuHasDSPR2)) {
    1161             :     InterpolateRow = InterpolateRow_Any_16_DSPR2;
    1162             :     if (IS_ALIGNED(src_width, 4)) {
    1163             :       InterpolateRow = InterpolateRow_16_DSPR2;
    1164             :     }
    1165             :   }
    1166             : #endif
    1167             : 
    1168             : #if defined(HAS_SCALEFILTERCOLS_16_SSSE3)
    1169             :   if (TestCpuFlag(kCpuHasSSSE3) && src_width < 32768) {
    1170             :     ScaleFilterCols = ScaleFilterCols_16_SSSE3;
    1171             :   }
    1172             : #endif
    1173           0 :   if (y > max_y) {
    1174           0 :     y = max_y;
    1175             :   }
    1176             : 
    1177           0 :   for (j = 0; j < dst_height; ++j) {
    1178           0 :     int yi = y >> 16;
    1179           0 :     const uint16* src = src_ptr + yi * src_stride;
    1180           0 :     if (filtering == kFilterLinear) {
    1181           0 :       ScaleFilterCols(dst_ptr, src, dst_width, x, dx);
    1182             :     } else {
    1183           0 :       int yf = (y >> 8) & 255;
    1184           0 :       InterpolateRow((uint16*)row, src, src_stride, src_width, yf);
    1185           0 :       ScaleFilterCols(dst_ptr, (uint16*)row, dst_width, x, dx);
    1186             :     }
    1187           0 :     dst_ptr += dst_stride;
    1188           0 :     y += dy;
    1189           0 :     if (y > max_y) {
    1190           0 :       y = max_y;
    1191             :     }
    1192             :   }
    1193           0 :   free_aligned_buffer_64(row);
    1194           0 : }
    1195             : 
    1196             : // Scale up down with bilinear interpolation.
    1197           0 : void ScalePlaneBilinearUp(int src_width,
    1198             :                           int src_height,
    1199             :                           int dst_width,
    1200             :                           int dst_height,
    1201             :                           int src_stride,
    1202             :                           int dst_stride,
    1203             :                           const uint8* src_ptr,
    1204             :                           uint8* dst_ptr,
    1205             :                           enum FilterMode filtering) {
    1206             :   int j;
    1207             :   // Initial source x/y coordinate and step values as 16.16 fixed point.
    1208           0 :   int x = 0;
    1209           0 :   int y = 0;
    1210           0 :   int dx = 0;
    1211           0 :   int dy = 0;
    1212           0 :   const int max_y = (src_height - 1) << 16;
    1213             :   void (*InterpolateRow)(uint8 * dst_ptr, const uint8* src_ptr,
    1214             :                          ptrdiff_t src_stride, int dst_width,
    1215           0 :                          int source_y_fraction) = InterpolateRow_C;
    1216             :   void (*ScaleFilterCols)(uint8 * dst_ptr, const uint8* src_ptr, int dst_width,
    1217             :                           int x, int dx) =
    1218           0 :       filtering ? ScaleFilterCols_C : ScaleCols_C;
    1219             :   ScaleSlope(src_width, src_height, dst_width, dst_height, filtering, &x, &y,
    1220           0 :              &dx, &dy);
    1221           0 :   src_width = Abs(src_width);
    1222             : 
    1223             : #if defined(HAS_INTERPOLATEROW_SSSE3)
    1224           0 :   if (TestCpuFlag(kCpuHasSSSE3)) {
    1225           0 :     InterpolateRow = InterpolateRow_Any_SSSE3;
    1226           0 :     if (IS_ALIGNED(dst_width, 16)) {
    1227           0 :       InterpolateRow = InterpolateRow_SSSE3;
    1228             :     }
    1229             :   }
    1230             : #endif
    1231             : #if defined(HAS_INTERPOLATEROW_AVX2)
    1232           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
    1233           0 :     InterpolateRow = InterpolateRow_Any_AVX2;
    1234           0 :     if (IS_ALIGNED(dst_width, 32)) {
    1235           0 :       InterpolateRow = InterpolateRow_AVX2;
    1236             :     }
    1237             :   }
    1238             : #endif
    1239             : #if defined(HAS_INTERPOLATEROW_NEON)
    1240             :   if (TestCpuFlag(kCpuHasNEON)) {
    1241             :     InterpolateRow = InterpolateRow_Any_NEON;
    1242             :     if (IS_ALIGNED(dst_width, 16)) {
    1243             :       InterpolateRow = InterpolateRow_NEON;
    1244             :     }
    1245             :   }
    1246             : #endif
    1247             : #if defined(HAS_INTERPOLATEROW_DSPR2)
    1248             :   if (TestCpuFlag(kCpuHasDSPR2)) {
    1249             :     InterpolateRow = InterpolateRow_Any_DSPR2;
    1250             :     if (IS_ALIGNED(dst_width, 4)) {
    1251             :       InterpolateRow = InterpolateRow_DSPR2;
    1252             :     }
    1253             :   }
    1254             : #endif
    1255             : 
    1256           0 :   if (filtering && src_width >= 32768) {
    1257           0 :     ScaleFilterCols = ScaleFilterCols64_C;
    1258             :   }
    1259             : #if defined(HAS_SCALEFILTERCOLS_SSSE3)
    1260           0 :   if (filtering && TestCpuFlag(kCpuHasSSSE3) && src_width < 32768) {
    1261           0 :     ScaleFilterCols = ScaleFilterCols_SSSE3;
    1262             :   }
    1263             : #endif
    1264             : #if defined(HAS_SCALEFILTERCOLS_NEON)
    1265             :   if (filtering && TestCpuFlag(kCpuHasNEON) && src_width < 32768) {
    1266             :     ScaleFilterCols = ScaleFilterCols_Any_NEON;
    1267             :     if (IS_ALIGNED(dst_width, 8)) {
    1268             :       ScaleFilterCols = ScaleFilterCols_NEON;
    1269             :     }
    1270             :   }
    1271             : #endif
    1272           0 :   if (!filtering && src_width * 2 == dst_width && x < 0x8000) {
    1273           0 :     ScaleFilterCols = ScaleColsUp2_C;
    1274             : #if defined(HAS_SCALECOLS_SSE2)
    1275             :     if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(dst_width, 8)) {
    1276             :       ScaleFilterCols = ScaleColsUp2_SSE2;
    1277             :     }
    1278             : #endif
    1279             :   }
    1280             : 
    1281           0 :   if (y > max_y) {
    1282           0 :     y = max_y;
    1283             :   }
    1284             :   {
    1285           0 :     int yi = y >> 16;
    1286           0 :     const uint8* src = src_ptr + yi * src_stride;
    1287             : 
    1288             :     // Allocate 2 row buffers.
    1289           0 :     const int kRowSize = (dst_width + 31) & ~31;
    1290           0 :     align_buffer_64(row, kRowSize * 2);
    1291             : 
    1292           0 :     uint8* rowptr = row;
    1293           0 :     int rowstride = kRowSize;
    1294           0 :     int lasty = yi;
    1295             : 
    1296           0 :     ScaleFilterCols(rowptr, src, dst_width, x, dx);
    1297           0 :     if (src_height > 1) {
    1298           0 :       src += src_stride;
    1299             :     }
    1300           0 :     ScaleFilterCols(rowptr + rowstride, src, dst_width, x, dx);
    1301           0 :     src += src_stride;
    1302             : 
    1303           0 :     for (j = 0; j < dst_height; ++j) {
    1304           0 :       yi = y >> 16;
    1305           0 :       if (yi != lasty) {
    1306           0 :         if (y > max_y) {
    1307           0 :           y = max_y;
    1308           0 :           yi = y >> 16;
    1309           0 :           src = src_ptr + yi * src_stride;
    1310             :         }
    1311           0 :         if (yi != lasty) {
    1312           0 :           ScaleFilterCols(rowptr, src, dst_width, x, dx);
    1313           0 :           rowptr += rowstride;
    1314           0 :           rowstride = -rowstride;
    1315           0 :           lasty = yi;
    1316           0 :           src += src_stride;
    1317             :         }
    1318             :       }
    1319           0 :       if (filtering == kFilterLinear) {
    1320           0 :         InterpolateRow(dst_ptr, rowptr, 0, dst_width, 0);
    1321             :       } else {
    1322           0 :         int yf = (y >> 8) & 255;
    1323           0 :         InterpolateRow(dst_ptr, rowptr, rowstride, dst_width, yf);
    1324             :       }
    1325           0 :       dst_ptr += dst_stride;
    1326           0 :       y += dy;
    1327             :     }
    1328           0 :     free_aligned_buffer_64(row);
    1329             :   }
    1330           0 : }
    1331             : 
    1332           0 : void ScalePlaneBilinearUp_16(int src_width,
    1333             :                              int src_height,
    1334             :                              int dst_width,
    1335             :                              int dst_height,
    1336             :                              int src_stride,
    1337             :                              int dst_stride,
    1338             :                              const uint16* src_ptr,
    1339             :                              uint16* dst_ptr,
    1340             :                              enum FilterMode filtering) {
    1341             :   int j;
    1342             :   // Initial source x/y coordinate and step values as 16.16 fixed point.
    1343           0 :   int x = 0;
    1344           0 :   int y = 0;
    1345           0 :   int dx = 0;
    1346           0 :   int dy = 0;
    1347           0 :   const int max_y = (src_height - 1) << 16;
    1348             :   void (*InterpolateRow)(uint16 * dst_ptr, const uint16* src_ptr,
    1349             :                          ptrdiff_t src_stride, int dst_width,
    1350           0 :                          int source_y_fraction) = InterpolateRow_16_C;
    1351             :   void (*ScaleFilterCols)(uint16 * dst_ptr, const uint16* src_ptr,
    1352             :                           int dst_width, int x, int dx) =
    1353           0 :       filtering ? ScaleFilterCols_16_C : ScaleCols_16_C;
    1354             :   ScaleSlope(src_width, src_height, dst_width, dst_height, filtering, &x, &y,
    1355           0 :              &dx, &dy);
    1356           0 :   src_width = Abs(src_width);
    1357             : 
    1358             : #if defined(HAS_INTERPOLATEROW_16_SSE2)
    1359             :   if (TestCpuFlag(kCpuHasSSE2)) {
    1360             :     InterpolateRow = InterpolateRow_Any_16_SSE2;
    1361             :     if (IS_ALIGNED(dst_width, 16)) {
    1362             :       InterpolateRow = InterpolateRow_16_SSE2;
    1363             :     }
    1364             :   }
    1365             : #endif
    1366             : #if defined(HAS_INTERPOLATEROW_16_SSSE3)
    1367             :   if (TestCpuFlag(kCpuHasSSSE3)) {
    1368             :     InterpolateRow = InterpolateRow_Any_16_SSSE3;
    1369             :     if (IS_ALIGNED(dst_width, 16)) {
    1370             :       InterpolateRow = InterpolateRow_16_SSSE3;
    1371             :     }
    1372             :   }
    1373             : #endif
    1374             : #if defined(HAS_INTERPOLATEROW_16_AVX2)
    1375             :   if (TestCpuFlag(kCpuHasAVX2)) {
    1376             :     InterpolateRow = InterpolateRow_Any_16_AVX2;
    1377             :     if (IS_ALIGNED(dst_width, 32)) {
    1378             :       InterpolateRow = InterpolateRow_16_AVX2;
    1379             :     }
    1380             :   }
    1381             : #endif
    1382             : #if defined(HAS_INTERPOLATEROW_16_NEON)
    1383             :   if (TestCpuFlag(kCpuHasNEON)) {
    1384             :     InterpolateRow = InterpolateRow_Any_16_NEON;
    1385             :     if (IS_ALIGNED(dst_width, 16)) {
    1386             :       InterpolateRow = InterpolateRow_16_NEON;
    1387             :     }
    1388             :   }
    1389             : #endif
    1390             : #if defined(HAS_INTERPOLATEROW_16_DSPR2)
    1391             :   if (TestCpuFlag(kCpuHasDSPR2)) {
    1392             :     InterpolateRow = InterpolateRow_Any_16_DSPR2;
    1393             :     if (IS_ALIGNED(dst_width, 4)) {
    1394             :       InterpolateRow = InterpolateRow_16_DSPR2;
    1395             :     }
    1396             :   }
    1397             : #endif
    1398             : 
    1399           0 :   if (filtering && src_width >= 32768) {
    1400           0 :     ScaleFilterCols = ScaleFilterCols64_16_C;
    1401             :   }
    1402             : #if defined(HAS_SCALEFILTERCOLS_16_SSSE3)
    1403             :   if (filtering && TestCpuFlag(kCpuHasSSSE3) && src_width < 32768) {
    1404             :     ScaleFilterCols = ScaleFilterCols_16_SSSE3;
    1405             :   }
    1406             : #endif
    1407           0 :   if (!filtering && src_width * 2 == dst_width && x < 0x8000) {
    1408           0 :     ScaleFilterCols = ScaleColsUp2_16_C;
    1409             : #if defined(HAS_SCALECOLS_16_SSE2)
    1410             :     if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(dst_width, 8)) {
    1411             :       ScaleFilterCols = ScaleColsUp2_16_SSE2;
    1412             :     }
    1413             : #endif
    1414             :   }
    1415             : 
    1416           0 :   if (y > max_y) {
    1417           0 :     y = max_y;
    1418             :   }
    1419             :   {
    1420           0 :     int yi = y >> 16;
    1421           0 :     const uint16* src = src_ptr + yi * src_stride;
    1422             : 
    1423             :     // Allocate 2 row buffers.
    1424           0 :     const int kRowSize = (dst_width + 31) & ~31;
    1425           0 :     align_buffer_64(row, kRowSize * 4);
    1426             : 
    1427           0 :     uint16* rowptr = (uint16*)row;
    1428           0 :     int rowstride = kRowSize;
    1429           0 :     int lasty = yi;
    1430             : 
    1431           0 :     ScaleFilterCols(rowptr, src, dst_width, x, dx);
    1432           0 :     if (src_height > 1) {
    1433           0 :       src += src_stride;
    1434             :     }
    1435           0 :     ScaleFilterCols(rowptr + rowstride, src, dst_width, x, dx);
    1436           0 :     src += src_stride;
    1437             : 
    1438           0 :     for (j = 0; j < dst_height; ++j) {
    1439           0 :       yi = y >> 16;
    1440           0 :       if (yi != lasty) {
    1441           0 :         if (y > max_y) {
    1442           0 :           y = max_y;
    1443           0 :           yi = y >> 16;
    1444           0 :           src = src_ptr + yi * src_stride;
    1445             :         }
    1446           0 :         if (yi != lasty) {
    1447           0 :           ScaleFilterCols(rowptr, src, dst_width, x, dx);
    1448           0 :           rowptr += rowstride;
    1449           0 :           rowstride = -rowstride;
    1450           0 :           lasty = yi;
    1451           0 :           src += src_stride;
    1452             :         }
    1453             :       }
    1454           0 :       if (filtering == kFilterLinear) {
    1455           0 :         InterpolateRow(dst_ptr, rowptr, 0, dst_width, 0);
    1456             :       } else {
    1457           0 :         int yf = (y >> 8) & 255;
    1458           0 :         InterpolateRow(dst_ptr, rowptr, rowstride, dst_width, yf);
    1459             :       }
    1460           0 :       dst_ptr += dst_stride;
    1461           0 :       y += dy;
    1462             :     }
    1463           0 :     free_aligned_buffer_64(row);
    1464             :   }
    1465           0 : }
    1466             : 
    1467             : // Scale Plane to/from any dimensions, without interpolation.
    1468             : // Fixed point math is used for performance: The upper 16 bits
    1469             : // of x and dx is the integer part of the source position and
    1470             : // the lower 16 bits are the fixed decimal part.
    1471             : 
    1472           0 : static void ScalePlaneSimple(int src_width,
    1473             :                              int src_height,
    1474             :                              int dst_width,
    1475             :                              int dst_height,
    1476             :                              int src_stride,
    1477             :                              int dst_stride,
    1478             :                              const uint8* src_ptr,
    1479             :                              uint8* dst_ptr) {
    1480             :   int i;
    1481             :   void (*ScaleCols)(uint8 * dst_ptr, const uint8* src_ptr, int dst_width, int x,
    1482           0 :                     int dx) = ScaleCols_C;
    1483             :   // Initial source x/y coordinate and step values as 16.16 fixed point.
    1484           0 :   int x = 0;
    1485           0 :   int y = 0;
    1486           0 :   int dx = 0;
    1487           0 :   int dy = 0;
    1488             :   ScaleSlope(src_width, src_height, dst_width, dst_height, kFilterNone, &x, &y,
    1489           0 :              &dx, &dy);
    1490           0 :   src_width = Abs(src_width);
    1491             : 
    1492           0 :   if (src_width * 2 == dst_width && x < 0x8000) {
    1493           0 :     ScaleCols = ScaleColsUp2_C;
    1494             : #if defined(HAS_SCALECOLS_SSE2)
    1495             :     if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(dst_width, 8)) {
    1496             :       ScaleCols = ScaleColsUp2_SSE2;
    1497             :     }
    1498             : #endif
    1499             :   }
    1500             : 
    1501           0 :   for (i = 0; i < dst_height; ++i) {
    1502           0 :     ScaleCols(dst_ptr, src_ptr + (y >> 16) * src_stride, dst_width, x, dx);
    1503           0 :     dst_ptr += dst_stride;
    1504           0 :     y += dy;
    1505             :   }
    1506           0 : }
    1507             : 
    1508           0 : static void ScalePlaneSimple_16(int src_width,
    1509             :                                 int src_height,
    1510             :                                 int dst_width,
    1511             :                                 int dst_height,
    1512             :                                 int src_stride,
    1513             :                                 int dst_stride,
    1514             :                                 const uint16* src_ptr,
    1515             :                                 uint16* dst_ptr) {
    1516             :   int i;
    1517             :   void (*ScaleCols)(uint16 * dst_ptr, const uint16* src_ptr, int dst_width,
    1518           0 :                     int x, int dx) = ScaleCols_16_C;
    1519             :   // Initial source x/y coordinate and step values as 16.16 fixed point.
    1520           0 :   int x = 0;
    1521           0 :   int y = 0;
    1522           0 :   int dx = 0;
    1523           0 :   int dy = 0;
    1524             :   ScaleSlope(src_width, src_height, dst_width, dst_height, kFilterNone, &x, &y,
    1525           0 :              &dx, &dy);
    1526           0 :   src_width = Abs(src_width);
    1527             : 
    1528           0 :   if (src_width * 2 == dst_width && x < 0x8000) {
    1529           0 :     ScaleCols = ScaleColsUp2_16_C;
    1530             : #if defined(HAS_SCALECOLS_16_SSE2)
    1531             :     if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(dst_width, 8)) {
    1532             :       ScaleCols = ScaleColsUp2_16_SSE2;
    1533             :     }
    1534             : #endif
    1535             :   }
    1536             : 
    1537           0 :   for (i = 0; i < dst_height; ++i) {
    1538           0 :     ScaleCols(dst_ptr, src_ptr + (y >> 16) * src_stride, dst_width, x, dx);
    1539           0 :     dst_ptr += dst_stride;
    1540           0 :     y += dy;
    1541             :   }
    1542           0 : }
    1543             : 
    1544             : // Scale a plane.
    1545             : // This function dispatches to a specialized scaler based on scale factor.
    1546             : 
    1547             : LIBYUV_API
    1548           0 : void ScalePlane(const uint8* src,
    1549             :                 int src_stride,
    1550             :                 int src_width,
    1551             :                 int src_height,
    1552             :                 uint8* dst,
    1553             :                 int dst_stride,
    1554             :                 int dst_width,
    1555             :                 int dst_height,
    1556             :                 enum FilterMode filtering) {
    1557             :   // Simplify filtering when possible.
    1558             :   filtering = ScaleFilterReduce(src_width, src_height, dst_width, dst_height,
    1559           0 :                                 filtering);
    1560             : 
    1561             :   // Negative height means invert the image.
    1562           0 :   if (src_height < 0) {
    1563           0 :     src_height = -src_height;
    1564           0 :     src = src + (src_height - 1) * src_stride;
    1565           0 :     src_stride = -src_stride;
    1566             :   }
    1567             : 
    1568             :   // Use specialized scales to improve performance for common resolutions.
    1569             :   // For example, all the 1/2 scalings will use ScalePlaneDown2()
    1570           0 :   if (dst_width == src_width && dst_height == src_height) {
    1571             :     // Straight copy.
    1572           0 :     CopyPlane(src, src_stride, dst, dst_stride, dst_width, dst_height);
    1573           0 :     return;
    1574             :   }
    1575           0 :   if (dst_width == src_width && filtering != kFilterBox) {
    1576           0 :     int dy = FixedDiv(src_height, dst_height);
    1577             :     // Arbitrary scale vertically, but unscaled horizontally.
    1578             :     ScalePlaneVertical(src_height, dst_width, dst_height, src_stride,
    1579           0 :                        dst_stride, src, dst, 0, 0, dy, 1, filtering);
    1580           0 :     return;
    1581             :   }
    1582           0 :   if (dst_width <= Abs(src_width) && dst_height <= src_height) {
    1583             :     // Scale down.
    1584           0 :     if (4 * dst_width == 3 * src_width && 4 * dst_height == 3 * src_height) {
    1585             :       // optimized, 3/4
    1586             :       ScalePlaneDown34(src_width, src_height, dst_width, dst_height, src_stride,
    1587           0 :                        dst_stride, src, dst, filtering);
    1588           0 :       return;
    1589             :     }
    1590           0 :     if (2 * dst_width == src_width && 2 * dst_height == src_height) {
    1591             :       // optimized, 1/2
    1592             :       ScalePlaneDown2(src_width, src_height, dst_width, dst_height, src_stride,
    1593           0 :                       dst_stride, src, dst, filtering);
    1594           0 :       return;
    1595             :     }
    1596             :     // 3/8 rounded up for odd sized chroma height.
    1597           0 :     if (8 * dst_width == 3 * src_width && 8 * dst_height == 3 * src_height) {
    1598             :       // optimized, 3/8
    1599             :       ScalePlaneDown38(src_width, src_height, dst_width, dst_height, src_stride,
    1600           0 :                        dst_stride, src, dst, filtering);
    1601           0 :       return;
    1602             :     }
    1603           0 :     if (4 * dst_width == src_width && 4 * dst_height == src_height &&
    1604           0 :         (filtering == kFilterBox || filtering == kFilterNone)) {
    1605             :       // optimized, 1/4
    1606             :       ScalePlaneDown4(src_width, src_height, dst_width, dst_height, src_stride,
    1607           0 :                       dst_stride, src, dst, filtering);
    1608           0 :       return;
    1609             :     }
    1610             :   }
    1611           0 :   if (filtering == kFilterBox && dst_height * 2 < src_height) {
    1612             :     ScalePlaneBox(src_width, src_height, dst_width, dst_height, src_stride,
    1613           0 :                   dst_stride, src, dst);
    1614           0 :     return;
    1615             :   }
    1616           0 :   if (filtering && dst_height > src_height) {
    1617             :     ScalePlaneBilinearUp(src_width, src_height, dst_width, dst_height,
    1618           0 :                          src_stride, dst_stride, src, dst, filtering);
    1619           0 :     return;
    1620             :   }
    1621           0 :   if (filtering) {
    1622             :     ScalePlaneBilinearDown(src_width, src_height, dst_width, dst_height,
    1623           0 :                            src_stride, dst_stride, src, dst, filtering);
    1624           0 :     return;
    1625             :   }
    1626             :   ScalePlaneSimple(src_width, src_height, dst_width, dst_height, src_stride,
    1627           0 :                    dst_stride, src, dst);
    1628             : }
    1629             : 
    1630             : LIBYUV_API
    1631           0 : void ScalePlane_16(const uint16* src,
    1632             :                    int src_stride,
    1633             :                    int src_width,
    1634             :                    int src_height,
    1635             :                    uint16* dst,
    1636             :                    int dst_stride,
    1637             :                    int dst_width,
    1638             :                    int dst_height,
    1639             :                    enum FilterMode filtering) {
    1640             :   // Simplify filtering when possible.
    1641             :   filtering = ScaleFilterReduce(src_width, src_height, dst_width, dst_height,
    1642           0 :                                 filtering);
    1643             : 
    1644             :   // Negative height means invert the image.
    1645           0 :   if (src_height < 0) {
    1646           0 :     src_height = -src_height;
    1647           0 :     src = src + (src_height - 1) * src_stride;
    1648           0 :     src_stride = -src_stride;
    1649             :   }
    1650             : 
    1651             :   // Use specialized scales to improve performance for common resolutions.
    1652             :   // For example, all the 1/2 scalings will use ScalePlaneDown2()
    1653           0 :   if (dst_width == src_width && dst_height == src_height) {
    1654             :     // Straight copy.
    1655           0 :     CopyPlane_16(src, src_stride, dst, dst_stride, dst_width, dst_height);
    1656           0 :     return;
    1657             :   }
    1658           0 :   if (dst_width == src_width) {
    1659           0 :     int dy = FixedDiv(src_height, dst_height);
    1660             :     // Arbitrary scale vertically, but unscaled vertically.
    1661             :     ScalePlaneVertical_16(src_height, dst_width, dst_height, src_stride,
    1662           0 :                           dst_stride, src, dst, 0, 0, dy, 1, filtering);
    1663           0 :     return;
    1664             :   }
    1665           0 :   if (dst_width <= Abs(src_width) && dst_height <= src_height) {
    1666             :     // Scale down.
    1667           0 :     if (4 * dst_width == 3 * src_width && 4 * dst_height == 3 * src_height) {
    1668             :       // optimized, 3/4
    1669             :       ScalePlaneDown34_16(src_width, src_height, dst_width, dst_height,
    1670           0 :                           src_stride, dst_stride, src, dst, filtering);
    1671           0 :       return;
    1672             :     }
    1673           0 :     if (2 * dst_width == src_width && 2 * dst_height == src_height) {
    1674             :       // optimized, 1/2
    1675             :       ScalePlaneDown2_16(src_width, src_height, dst_width, dst_height,
    1676           0 :                          src_stride, dst_stride, src, dst, filtering);
    1677           0 :       return;
    1678             :     }
    1679             :     // 3/8 rounded up for odd sized chroma height.
    1680           0 :     if (8 * dst_width == 3 * src_width && 8 * dst_height == 3 * src_height) {
    1681             :       // optimized, 3/8
    1682             :       ScalePlaneDown38_16(src_width, src_height, dst_width, dst_height,
    1683           0 :                           src_stride, dst_stride, src, dst, filtering);
    1684           0 :       return;
    1685             :     }
    1686           0 :     if (4 * dst_width == src_width && 4 * dst_height == src_height &&
    1687             :         filtering != kFilterBilinear) {
    1688             :       // optimized, 1/4
    1689             :       ScalePlaneDown4_16(src_width, src_height, dst_width, dst_height,
    1690           0 :                          src_stride, dst_stride, src, dst, filtering);
    1691           0 :       return;
    1692             :     }
    1693             :   }
    1694           0 :   if (filtering == kFilterBox && dst_height * 2 < src_height) {
    1695             :     ScalePlaneBox_16(src_width, src_height, dst_width, dst_height, src_stride,
    1696           0 :                      dst_stride, src, dst);
    1697           0 :     return;
    1698             :   }
    1699           0 :   if (filtering && dst_height > src_height) {
    1700             :     ScalePlaneBilinearUp_16(src_width, src_height, dst_width, dst_height,
    1701           0 :                             src_stride, dst_stride, src, dst, filtering);
    1702           0 :     return;
    1703             :   }
    1704           0 :   if (filtering) {
    1705             :     ScalePlaneBilinearDown_16(src_width, src_height, dst_width, dst_height,
    1706           0 :                               src_stride, dst_stride, src, dst, filtering);
    1707           0 :     return;
    1708             :   }
    1709             :   ScalePlaneSimple_16(src_width, src_height, dst_width, dst_height, src_stride,
    1710           0 :                       dst_stride, src, dst);
    1711             : }
    1712             : 
    1713             : // Scale an I420 image.
    1714             : // This function in turn calls a scaling function for each plane.
    1715             : 
    1716             : LIBYUV_API
    1717           0 : int I420Scale(const uint8* src_y,
    1718             :               int src_stride_y,
    1719             :               const uint8* src_u,
    1720             :               int src_stride_u,
    1721             :               const uint8* src_v,
    1722             :               int src_stride_v,
    1723             :               int src_width,
    1724             :               int src_height,
    1725             :               uint8* dst_y,
    1726             :               int dst_stride_y,
    1727             :               uint8* dst_u,
    1728             :               int dst_stride_u,
    1729             :               uint8* dst_v,
    1730             :               int dst_stride_v,
    1731             :               int dst_width,
    1732             :               int dst_height,
    1733             :               enum FilterMode filtering) {
    1734           0 :   int src_halfwidth = SUBSAMPLE(src_width, 1, 1);
    1735           0 :   int src_halfheight = SUBSAMPLE(src_height, 1, 1);
    1736           0 :   int dst_halfwidth = SUBSAMPLE(dst_width, 1, 1);
    1737           0 :   int dst_halfheight = SUBSAMPLE(dst_height, 1, 1);
    1738           0 :   if (!src_y || !src_u || !src_v || src_width == 0 || src_height == 0 ||
    1739           0 :       src_width > 32768 || src_height > 32768 || !dst_y || !dst_u || !dst_v ||
    1740           0 :       dst_width <= 0 || dst_height <= 0) {
    1741           0 :     return -1;
    1742             :   }
    1743             : 
    1744             :   ScalePlane(src_y, src_stride_y, src_width, src_height, dst_y, dst_stride_y,
    1745           0 :              dst_width, dst_height, filtering);
    1746             :   ScalePlane(src_u, src_stride_u, src_halfwidth, src_halfheight, dst_u,
    1747           0 :              dst_stride_u, dst_halfwidth, dst_halfheight, filtering);
    1748             :   ScalePlane(src_v, src_stride_v, src_halfwidth, src_halfheight, dst_v,
    1749           0 :              dst_stride_v, dst_halfwidth, dst_halfheight, filtering);
    1750           0 :   return 0;
    1751             : }
    1752             : 
    1753             : LIBYUV_API
    1754           0 : int I420Scale_16(const uint16* src_y,
    1755             :                  int src_stride_y,
    1756             :                  const uint16* src_u,
    1757             :                  int src_stride_u,
    1758             :                  const uint16* src_v,
    1759             :                  int src_stride_v,
    1760             :                  int src_width,
    1761             :                  int src_height,
    1762             :                  uint16* dst_y,
    1763             :                  int dst_stride_y,
    1764             :                  uint16* dst_u,
    1765             :                  int dst_stride_u,
    1766             :                  uint16* dst_v,
    1767             :                  int dst_stride_v,
    1768             :                  int dst_width,
    1769             :                  int dst_height,
    1770             :                  enum FilterMode filtering) {
    1771           0 :   int src_halfwidth = SUBSAMPLE(src_width, 1, 1);
    1772           0 :   int src_halfheight = SUBSAMPLE(src_height, 1, 1);
    1773           0 :   int dst_halfwidth = SUBSAMPLE(dst_width, 1, 1);
    1774           0 :   int dst_halfheight = SUBSAMPLE(dst_height, 1, 1);
    1775           0 :   if (!src_y || !src_u || !src_v || src_width == 0 || src_height == 0 ||
    1776           0 :       src_width > 32768 || src_height > 32768 || !dst_y || !dst_u || !dst_v ||
    1777           0 :       dst_width <= 0 || dst_height <= 0) {
    1778           0 :     return -1;
    1779             :   }
    1780             : 
    1781             :   ScalePlane_16(src_y, src_stride_y, src_width, src_height, dst_y, dst_stride_y,
    1782           0 :                 dst_width, dst_height, filtering);
    1783             :   ScalePlane_16(src_u, src_stride_u, src_halfwidth, src_halfheight, dst_u,
    1784           0 :                 dst_stride_u, dst_halfwidth, dst_halfheight, filtering);
    1785             :   ScalePlane_16(src_v, src_stride_v, src_halfwidth, src_halfheight, dst_v,
    1786           0 :                 dst_stride_v, dst_halfwidth, dst_halfheight, filtering);
    1787           0 :   return 0;
    1788             : }
    1789             : 
    1790             : // Deprecated api
    1791             : LIBYUV_API
    1792           0 : int Scale(const uint8* src_y,
    1793             :           const uint8* src_u,
    1794             :           const uint8* src_v,
    1795             :           int src_stride_y,
    1796             :           int src_stride_u,
    1797             :           int src_stride_v,
    1798             :           int src_width,
    1799             :           int src_height,
    1800             :           uint8* dst_y,
    1801             :           uint8* dst_u,
    1802             :           uint8* dst_v,
    1803             :           int dst_stride_y,
    1804             :           int dst_stride_u,
    1805             :           int dst_stride_v,
    1806             :           int dst_width,
    1807             :           int dst_height,
    1808             :           LIBYUV_BOOL interpolate) {
    1809           0 :   return I420Scale(src_y, src_stride_y, src_u, src_stride_u, src_v,
    1810             :                    src_stride_v, src_width, src_height, dst_y, dst_stride_y,
    1811             :                    dst_u, dst_stride_u, dst_v, dst_stride_v, dst_width,
    1812           0 :                    dst_height, interpolate ? kFilterBox : kFilterNone);
    1813             : }
    1814             : 
    1815             : // Deprecated api
    1816             : LIBYUV_API
    1817           0 : int ScaleOffset(const uint8* src,
    1818             :                 int src_width,
    1819             :                 int src_height,
    1820             :                 uint8* dst,
    1821             :                 int dst_width,
    1822             :                 int dst_height,
    1823             :                 int dst_yoffset,
    1824             :                 LIBYUV_BOOL interpolate) {
    1825             :   // Chroma requires offset to multiple of 2.
    1826           0 :   int dst_yoffset_even = dst_yoffset & ~1;
    1827           0 :   int src_halfwidth = SUBSAMPLE(src_width, 1, 1);
    1828           0 :   int src_halfheight = SUBSAMPLE(src_height, 1, 1);
    1829           0 :   int dst_halfwidth = SUBSAMPLE(dst_width, 1, 1);
    1830           0 :   int dst_halfheight = SUBSAMPLE(dst_height, 1, 1);
    1831           0 :   int aheight = dst_height - dst_yoffset_even * 2;  // actual output height
    1832           0 :   const uint8* src_y = src;
    1833           0 :   const uint8* src_u = src + src_width * src_height;
    1834             :   const uint8* src_v =
    1835           0 :       src + src_width * src_height + src_halfwidth * src_halfheight;
    1836           0 :   uint8* dst_y = dst + dst_yoffset_even * dst_width;
    1837             :   uint8* dst_u =
    1838           0 :       dst + dst_width * dst_height + (dst_yoffset_even >> 1) * dst_halfwidth;
    1839           0 :   uint8* dst_v = dst + dst_width * dst_height + dst_halfwidth * dst_halfheight +
    1840           0 :                  (dst_yoffset_even >> 1) * dst_halfwidth;
    1841           0 :   if (!src || src_width <= 0 || src_height <= 0 || !dst || dst_width <= 0 ||
    1842           0 :       dst_height <= 0 || dst_yoffset_even < 0 ||
    1843             :       dst_yoffset_even >= dst_height) {
    1844           0 :     return -1;
    1845             :   }
    1846           0 :   return I420Scale(src_y, src_width, src_u, src_halfwidth, src_v, src_halfwidth,
    1847             :                    src_width, src_height, dst_y, dst_width, dst_u,
    1848             :                    dst_halfwidth, dst_v, dst_halfwidth, dst_width, aheight,
    1849           0 :                    interpolate ? kFilterBox : kFilterNone);
    1850             : }
    1851             : 
    1852             : #ifdef __cplusplus
    1853             : }  // extern "C"
    1854             : }  // namespace libyuv
    1855             : #endif

Generated by: LCOV version 1.13